diff options
author | OpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com> | 2020-04-16 14:04:58 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-16 14:04:58 -0700 |
commit | 0d2b5532c417c58bd24e71a56c5c55b43e423a59 (patch) | |
tree | 4001e8e47a022bb1b9bfbf2332c42e1aeb802f9e /pkg/adapter/pods.go | |
parent | 88c6fd06cd54fb9a8826306dfdf1a77e400de5de (diff) | |
parent | 241326a9a8c20ad7f2bcf651416b836e7778e090 (diff) | |
download | podman-0d2b5532c417c58bd24e71a56c5c55b43e423a59.tar.gz podman-0d2b5532c417c58bd24e71a56c5c55b43e423a59.tar.bz2 podman-0d2b5532c417c58bd24e71a56c5c55b43e423a59.zip |
Merge pull request #5852 from baude/v1prune
Podman V2 birth
Diffstat (limited to 'pkg/adapter/pods.go')
-rw-r--r-- | pkg/adapter/pods.go | 1065 |
1 files changed, 0 insertions, 1065 deletions
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go deleted file mode 100644 index 7c2a84cc7..000000000 --- a/pkg/adapter/pods.go +++ /dev/null @@ -1,1065 +0,0 @@ -// +build !remoteclient - -package adapter - -import ( - "context" - "fmt" - "io" - "io/ioutil" - "net" - "os" - "path/filepath" - "strings" - - "github.com/containers/buildah/pkg/parse" - "github.com/containers/image/v5/docker/reference" - "github.com/containers/image/v5/types" - "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/cmd/podman/shared" - "github.com/containers/libpod/libpod" - "github.com/containers/libpod/libpod/define" - "github.com/containers/libpod/libpod/image" - "github.com/containers/libpod/pkg/adapter/shortcuts" - ann "github.com/containers/libpod/pkg/annotations" - envLib "github.com/containers/libpod/pkg/env" - ns "github.com/containers/libpod/pkg/namespaces" - createconfig "github.com/containers/libpod/pkg/spec" - "github.com/containers/libpod/pkg/util" - "github.com/containers/storage" - "github.com/cri-o/ocicni/pkg/ocicni" - "github.com/ghodss/yaml" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - v1 "k8s.io/api/core/v1" -) - -const ( - // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath - createDirectoryPermission = 0755 - // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath - createFilePermission = 0644 -) - -// PodContainerStats is struct containing an adapter Pod and a libpod -// ContainerStats and is used primarily for outputting pod stats. -type PodContainerStats struct { - Pod *Pod - ContainerStats map[string]*libpod.ContainerStats -} - -// PrunePods removes pods -func (r *LocalRuntime) PrunePods(ctx context.Context, cli *cliconfig.PodPruneValues) ([]string, map[string]error, error) { - var ( - ok = []string{} - failures = map[string]error{} - ) - - maxWorkers := shared.DefaultPoolSize("rm") - if cli.GlobalIsSet("max-workers") { - maxWorkers = cli.GlobalFlags.MaxWorks - } - logrus.Debugf("Setting maximum rm workers to %d", maxWorkers) - - states := []string{define.PodStateStopped, define.PodStateExited} - if cli.Force { - states = append(states, define.PodStateRunning) - } - - pods, err := r.GetPodsByStatus(states) - if err != nil { - return ok, failures, err - } - if len(pods) < 1 { - return ok, failures, nil - } - - pool := shared.NewPool("pod_prune", maxWorkers, len(pods)) - for _, p := range pods { - p := p - - pool.Add(shared.Job{ - ID: p.ID(), - Fn: func() error { - err := r.Runtime.RemovePod(ctx, p, true, cli.Force) - if err != nil { - logrus.Debugf("Failed to remove pod %s: %s", p.ID(), err.Error()) - } - return err - }, - }) - } - return pool.Run() -} - -// RemovePods ... -func (r *LocalRuntime) RemovePods(ctx context.Context, cli *cliconfig.PodRmValues) ([]string, []error) { - var ( - errs []error - podids []string - ) - pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime) - if err != nil && !(cli.Ignore && errors.Cause(err) == define.ErrNoSuchPod) { - errs = append(errs, err) - return nil, errs - } - - for _, p := range pods { - if err := r.Runtime.RemovePod(ctx, p, true, cli.Force); err != nil { - errs = append(errs, err) - } else { - podids = append(podids, p.ID()) - } - } - return podids, errs -} - -// GetLatestPod gets the latest pod and wraps it in an adapter pod -func (r *LocalRuntime) GetLatestPod() (*Pod, error) { - pod := Pod{} - p, err := r.Runtime.GetLatestPod() - pod.Pod = p - return &pod, err -} - -// GetPodsWithFilters gets the filtered list of pods based on the filter parameters provided. -func (r *LocalRuntime) GetPodsWithFilters(filters string) ([]*Pod, error) { - pods, err := shared.GetPodsWithFilters(r.Runtime, filters) - if err != nil { - return nil, err - } - return r.podstoAdapterPods(pods) -} - -func (r *LocalRuntime) podstoAdapterPods(pod []*libpod.Pod) ([]*Pod, error) { - var pods []*Pod - for _, i := range pod { - - pods = append(pods, &Pod{i}) - } - return pods, nil -} - -// GetAllPods gets all pods and wraps it in an adapter pod -func (r *LocalRuntime) GetAllPods() ([]*Pod, error) { - allPods, err := r.Runtime.GetAllPods() - if err != nil { - return nil, err - } - return r.podstoAdapterPods(allPods) -} - -// LookupPod gets a pod by name or id and wraps it in an adapter pod -func (r *LocalRuntime) LookupPod(nameOrID string) (*Pod, error) { - pod := Pod{} - p, err := r.Runtime.LookupPod(nameOrID) - pod.Pod = p - return &pod, err -} - -// StopPods is a wrapper to libpod to stop pods based on a cli context -func (r *LocalRuntime) StopPods(ctx context.Context, cli *cliconfig.PodStopValues) ([]string, []error) { - timeout := -1 - if cli.Flags().Changed("timeout") { - timeout = int(cli.Timeout) - } - var ( - errs []error - podids []string - ) - pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime) - if err != nil && !(cli.Ignore && errors.Cause(err) == define.ErrNoSuchPod) { - errs = append(errs, err) - return nil, errs - } - - for _, p := range pods { - stopped := true - conErrs, stopErr := p.StopWithTimeout(ctx, true, timeout) - if stopErr != nil { - errs = append(errs, stopErr) - stopped = false - } - if conErrs != nil { - stopped = false - for _, err := range conErrs { - errs = append(errs, err) - } - } - if stopped { - podids = append(podids, p.ID()) - } - } - return podids, errs -} - -// KillPods is a wrapper to libpod to start pods based on the cli context -func (r *LocalRuntime) KillPods(ctx context.Context, cli *cliconfig.PodKillValues, signal uint) ([]string, []error) { - var ( - errs []error - podids []string - ) - pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime) - if err != nil { - errs = append(errs, err) - return nil, errs - } - for _, p := range pods { - killed := true - conErrs, killErr := p.Kill(signal) - if killErr != nil { - errs = append(errs, killErr) - killed = false - } - if conErrs != nil { - killed = false - for _, err := range conErrs { - errs = append(errs, err) - } - } - if killed { - podids = append(podids, p.ID()) - } - } - return podids, errs -} - -// StartPods is a wrapper to start pods based on the cli context -func (r *LocalRuntime) StartPods(ctx context.Context, cli *cliconfig.PodStartValues) ([]string, []error) { - var ( - errs []error - podids []string - ) - pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime) - if err != nil { - errs = append(errs, err) - return nil, errs - } - for _, p := range pods { - started := true - conErrs, startErr := p.Start(ctx) - if startErr != nil { - errs = append(errs, startErr) - started = false - } - if conErrs != nil { - started = false - for _, err := range conErrs { - errs = append(errs, err) - } - } - if started { - podids = append(podids, p.ID()) - } - } - return podids, errs -} - -// CreatePod is a wrapper for libpod and creating a new pod from the cli context -func (r *LocalRuntime) CreatePod(ctx context.Context, cli *cliconfig.PodCreateValues, labels map[string]string) (string, error) { - var ( - options []libpod.PodCreateOption - err error - ) - - // This needs to be first, as a lot of options depend on - // WithInfraContainer() - if cli.Infra { - options = append(options, libpod.WithInfraContainer()) - nsOptions, err := shared.GetNamespaceOptions(strings.Split(cli.Share, ",")) - if err != nil { - return "", err - } - options = append(options, nsOptions...) - } - - if cli.Flag("cgroup-parent").Changed { - options = append(options, libpod.WithPodCgroupParent(cli.CgroupParent)) - } - - if len(labels) != 0 { - options = append(options, libpod.WithPodLabels(labels)) - } - - if cli.Flag("name").Changed { - options = append(options, libpod.WithPodName(cli.Name)) - } - - if cli.Flag("hostname").Changed { - options = append(options, libpod.WithPodHostname(cli.Hostname)) - } - - if cli.Flag("add-host").Changed { - options = append(options, libpod.WithPodHosts(cli.StringSlice("add-host"))) - } - if cli.Flag("dns").Changed { - dns := cli.StringSlice("dns") - foundHost := false - for _, entry := range dns { - if entry == "host" { - foundHost = true - } - } - if foundHost && len(dns) > 1 { - return "", errors.Errorf("cannot set dns=host and still provide other DNS servers") - } - if foundHost { - options = append(options, libpod.WithPodUseImageResolvConf()) - } else { - options = append(options, libpod.WithPodDNS(cli.StringSlice("dns"))) - } - } - if cli.Flag("dns-opt").Changed { - options = append(options, libpod.WithPodDNSOption(cli.StringSlice("dns-opt"))) - } - if cli.Flag("dns-search").Changed { - options = append(options, libpod.WithPodDNSSearch(cli.StringSlice("dns-search"))) - } - if cli.Flag("ip").Changed { - ip := net.ParseIP(cli.String("ip")) - if ip == nil { - return "", errors.Errorf("invalid IP address %q passed to --ip", cli.String("ip")) - } - - options = append(options, libpod.WithPodStaticIP(ip)) - } - if cli.Flag("mac-address").Changed { - mac, err := net.ParseMAC(cli.String("mac-address")) - if err != nil { - return "", errors.Wrapf(err, "invalid MAC address %q passed to --mac-address", cli.String("mac-address")) - } - - options = append(options, libpod.WithPodStaticMAC(mac)) - } - if cli.Flag("network").Changed { - netValue := cli.String("network") - switch strings.ToLower(netValue) { - case "bridge": - // Do nothing. - // TODO: Maybe this should be split between slirp and - // bridge? Better to wait until someone asks... - logrus.Debugf("Pod using default network mode") - case "host": - logrus.Debugf("Pod will use host networking") - options = append(options, libpod.WithPodHostNetwork()) - case "": - return "", errors.Errorf("invalid value passed to --network: must provide a comma-separated list of CNI networks or host") - default: - // We'll assume this is a comma-separated list of CNI - // networks. - networks := strings.Split(netValue, ",") - logrus.Debugf("Pod joining CNI networks: %v", networks) - options = append(options, libpod.WithPodNetworks(networks)) - } - } - if cli.Flag("no-hosts").Changed { - if cli.Bool("no-hosts") { - options = append(options, libpod.WithPodUseImageHosts()) - } - } - - publish := cli.StringSlice("publish") - if len(publish) > 0 { - portBindings, err := shared.CreatePortBindings(publish) - if err != nil { - return "", err - } - options = append(options, libpod.WithInfraContainerPorts(portBindings)) - - } - // always have containers use pod cgroups - // User Opt out is not yet supported - options = append(options, libpod.WithPodCgroups()) - - pod, err := r.NewPod(ctx, options...) - if err != nil { - return "", err - } - return pod.ID(), nil -} - -// GetPodStatus is a wrapper to get the status of a local libpod pod -func (p *Pod) GetPodStatus() (string, error) { - return shared.GetPodStatus(p.Pod) -} - -// BatchContainerOp is a wrapper for the shared function of the same name -func BatchContainerOp(ctr *libpod.Container, opts shared.PsOptions) (shared.BatchContainerStruct, error) { - return shared.BatchContainerOp(ctr, opts) -} - -// PausePods is a wrapper for pausing pods via libpod -func (r *LocalRuntime) PausePods(c *cliconfig.PodPauseValues) ([]string, map[string]error, []error) { - var ( - pauseIDs []string - pauseErrors []error - ) - containerErrors := make(map[string]error) - - pods, err := shortcuts.GetPodsByContext(c.All, c.Latest, c.InputArgs, r.Runtime) - if err != nil { - pauseErrors = append(pauseErrors, err) - return nil, containerErrors, pauseErrors - } - - for _, pod := range pods { - ctrErrs, err := pod.Pause() - if err != nil { - pauseErrors = append(pauseErrors, err) - continue - } - if ctrErrs != nil { - for ctr, err := range ctrErrs { - containerErrors[ctr] = err - } - continue - } - pauseIDs = append(pauseIDs, pod.ID()) - - } - return pauseIDs, containerErrors, pauseErrors -} - -// UnpausePods is a wrapper for unpausing pods via libpod -func (r *LocalRuntime) UnpausePods(c *cliconfig.PodUnpauseValues) ([]string, map[string]error, []error) { - var ( - unpauseIDs []string - unpauseErrors []error - ) - containerErrors := make(map[string]error) - - pods, err := shortcuts.GetPodsByContext(c.All, c.Latest, c.InputArgs, r.Runtime) - if err != nil { - unpauseErrors = append(unpauseErrors, err) - return nil, containerErrors, unpauseErrors - } - - for _, pod := range pods { - ctrErrs, err := pod.Unpause() - if err != nil { - unpauseErrors = append(unpauseErrors, err) - continue - } - if ctrErrs != nil { - for ctr, err := range ctrErrs { - containerErrors[ctr] = err - } - continue - } - unpauseIDs = append(unpauseIDs, pod.ID()) - - } - return unpauseIDs, containerErrors, unpauseErrors -} - -// RestartPods is a wrapper to restart pods via libpod -func (r *LocalRuntime) RestartPods(ctx context.Context, c *cliconfig.PodRestartValues) ([]string, map[string]error, []error) { - var ( - restartIDs []string - restartErrors []error - ) - containerErrors := make(map[string]error) - - pods, err := shortcuts.GetPodsByContext(c.All, c.Latest, c.InputArgs, r.Runtime) - if err != nil { - restartErrors = append(restartErrors, err) - return nil, containerErrors, restartErrors - } - - for _, pod := range pods { - ctrErrs, err := pod.Restart(ctx) - if err != nil { - restartErrors = append(restartErrors, err) - continue - } - if ctrErrs != nil { - for ctr, err := range ctrErrs { - containerErrors[ctr] = err - } - continue - } - restartIDs = append(restartIDs, pod.ID()) - - } - return restartIDs, containerErrors, restartErrors - -} - -// PodTop is a wrapper function to call GetPodPidInformation in libpod and return its results -// for output -func (r *LocalRuntime) PodTop(c *cliconfig.PodTopValues, descriptors []string) ([]string, error) { - var ( - pod *Pod - err error - ) - - if c.Latest { - pod, err = r.GetLatestPod() - } else { - pod, err = r.LookupPod(c.InputArgs[0]) - } - if err != nil { - return nil, errors.Wrapf(err, "unable to lookup requested container") - } - podStatus, err := pod.GetPodStatus() - if err != nil { - return nil, errors.Wrapf(err, "unable to get status for pod %s", pod.ID()) - } - if podStatus != "Running" { - return nil, errors.Errorf("pod top can only be used on pods with at least one running container") - } - return pod.GetPodPidInformation(descriptors) -} - -// GetStatPods returns pods for use in pod stats -func (r *LocalRuntime) GetStatPods(c *cliconfig.PodStatsValues) ([]*Pod, error) { - var ( - adapterPods []*Pod - pods []*libpod.Pod - err error - ) - - if len(c.InputArgs) > 0 || c.Latest || c.All { - pods, err = shortcuts.GetPodsByContext(c.All, c.Latest, c.InputArgs, r.Runtime) - } else { - pods, err = r.Runtime.GetRunningPods() - } - if err != nil { - return nil, err - } - // convert libpod pods to adapter pods - for _, p := range pods { - adapterPod := Pod{ - p, - } - adapterPods = append(adapterPods, &adapterPod) - } - return adapterPods, nil -} - -// PlayKubeYAML creates pods and containers from a kube YAML file -func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayValues, yamlFile string) (*Pod, error) { - var ( - containers []*libpod.Container - pod *libpod.Pod - podOptions []libpod.PodCreateOption - podYAML v1.Pod - registryCreds *types.DockerAuthConfig - writer io.Writer - ) - - content, err := ioutil.ReadFile(yamlFile) - if err != nil { - return nil, err - } - - if err := yaml.Unmarshal(content, &podYAML); err != nil { - return nil, errors.Wrapf(err, "unable to read %s as YAML", yamlFile) - } - - if podYAML.Kind != "Pod" { - return nil, errors.Errorf("Invalid YAML kind: %s. Pod is the only supported Kubernetes YAML kind", podYAML.Kind) - } - - // check for name collision between pod and container - podName := podYAML.ObjectMeta.Name - if podName == "" { - return nil, errors.Errorf("pod does not have a name") - } - for _, n := range podYAML.Spec.Containers { - if n.Name == podName { - fmt.Printf("a container exists with the same name (%s) as the pod in your YAML file; changing pod name to %s_pod\n", podName, podName) - podName = fmt.Sprintf("%s_pod", podName) - } - } - - podOptions = append(podOptions, libpod.WithInfraContainer()) - podOptions = append(podOptions, libpod.WithPodName(podName)) - // TODO for now we just used the default kernel namespaces; we need to add/subtract this from yaml - - hostname := podYAML.Spec.Hostname - if hostname == "" { - hostname = podName - } - podOptions = append(podOptions, libpod.WithPodHostname(hostname)) - - if podYAML.Spec.HostNetwork { - podOptions = append(podOptions, libpod.WithPodHostNetwork()) - } - - nsOptions, err := shared.GetNamespaceOptions(strings.Split(shared.DefaultKernelNamespaces, ",")) - if err != nil { - return nil, err - } - podOptions = append(podOptions, nsOptions...) - podPorts := getPodPorts(podYAML.Spec.Containers) - podOptions = append(podOptions, libpod.WithInfraContainerPorts(podPorts)) - - if c.Flag("network").Changed { - netValue := c.String("network") - switch strings.ToLower(netValue) { - case "bridge", "host": - return nil, errors.Errorf("invalid value passed to --network: bridge or host networking must be configured in YAML") - case "": - return nil, errors.Errorf("invalid value passed to --network: must provide a comma-separated list of CNI networks") - default: - // We'll assume this is a comma-separated list of CNI - // networks. - networks := strings.Split(netValue, ",") - logrus.Debugf("Pod joining CNI networks: %v", networks) - podOptions = append(podOptions, libpod.WithPodNetworks(networks)) - } - } - - // Create the Pod - pod, err = r.NewPod(ctx, podOptions...) - if err != nil { - return nil, err - } - - podInfraID, err := pod.InfraContainerID() - if err != nil { - return nil, err - } - hasUserns := false - if podInfraID != "" { - podCtr, err := r.GetContainer(podInfraID) - if err != nil { - return nil, err - } - mappings, err := podCtr.IDMappings() - if err != nil { - return nil, err - } - hasUserns = len(mappings.UIDMap) > 0 - } - - namespaces := map[string]string{ - // Disabled during code review per mheon - //"pid": fmt.Sprintf("container:%s", podInfraID), - "net": fmt.Sprintf("container:%s", podInfraID), - "ipc": fmt.Sprintf("container:%s", podInfraID), - "uts": fmt.Sprintf("container:%s", podInfraID), - } - if hasUserns { - namespaces["user"] = fmt.Sprintf("container:%s", podInfraID) - } - if !c.Quiet { - writer = os.Stderr - } - - dockerRegistryOptions := image.DockerRegistryOptions{ - DockerRegistryCreds: registryCreds, - DockerCertPath: c.CertDir, - } - if c.Flag("tls-verify").Changed { - dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.TlsVerify) - } - - // map from name to mount point - volumes := make(map[string]string) - for _, volume := range podYAML.Spec.Volumes { - hostPath := volume.VolumeSource.HostPath - if hostPath == nil { - return nil, errors.Errorf("HostPath is currently the only supported VolumeSource") - } - if hostPath.Type != nil { - switch *hostPath.Type { - case v1.HostPathDirectoryOrCreate: - if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) { - if err := os.Mkdir(hostPath.Path, createDirectoryPermission); err != nil { - return nil, errors.Errorf("Error creating HostPath %s at %s", volume.Name, hostPath.Path) - } - } - // Label a newly created volume - if err := libpod.LabelVolumePath(hostPath.Path); err != nil { - return nil, errors.Wrapf(err, "Error giving %s a label", hostPath.Path) - } - case v1.HostPathFileOrCreate: - if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) { - f, err := os.OpenFile(hostPath.Path, os.O_RDONLY|os.O_CREATE, createFilePermission) - if err != nil { - return nil, errors.Errorf("Error creating HostPath %s at %s", volume.Name, hostPath.Path) - } - if err := f.Close(); err != nil { - logrus.Warnf("Error in closing newly created HostPath file: %v", err) - } - } - // unconditionally label a newly created volume - if err := libpod.LabelVolumePath(hostPath.Path); err != nil { - return nil, errors.Wrapf(err, "Error giving %s a label", hostPath.Path) - } - case v1.HostPathDirectory: - case v1.HostPathFile: - case v1.HostPathUnset: - // do nothing here because we will verify the path exists in validateVolumeHostDir - break - default: - return nil, errors.Errorf("Directories are the only supported HostPath type") - } - } - - if err := parse.ValidateVolumeHostDir(hostPath.Path); err != nil { - return nil, errors.Wrapf(err, "Error in parsing HostPath in YAML") - } - volumes[volume.Name] = hostPath.Path - } - - seccompPaths, err := initializeSeccompPaths(podYAML.ObjectMeta.Annotations, c.SeccompProfileRoot) - if err != nil { - return nil, err - } - - for _, container := range podYAML.Spec.Containers { - pullPolicy := util.PullImageMissing - if len(container.ImagePullPolicy) > 0 { - pullPolicy, err = util.ValidatePullType(string(container.ImagePullPolicy)) - if err != nil { - return nil, err - } - } - named, err := reference.ParseNormalizedNamed(container.Image) - if err != nil { - return nil, err - } - // In kube, if the image is tagged with latest, it should always pull - if tagged, isTagged := named.(reference.NamedTagged); isTagged { - if tagged.Tag() == image.LatestTag { - pullPolicy = util.PullImageAlways - } - } - newImage, err := r.ImageRuntime().New(ctx, container.Image, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullPolicy) - if err != nil { - return nil, err - } - createConfig, err := kubeContainerToCreateConfig(ctx, container, r.Runtime, newImage, namespaces, volumes, pod.ID(), podInfraID, seccompPaths) - if err != nil { - return nil, err - } - ctr, err := shared.CreateContainerFromCreateConfig(r.Runtime, createConfig, ctx, pod) - if err != nil { - return nil, err - } - containers = append(containers, ctr) - } - - // start the containers - for _, ctr := range containers { - if err := ctr.Start(ctx, true); err != nil { - // Making this a hard failure here to avoid a mess - // the other containers are in created status - return nil, err - } - } - - // We've now successfully converted this YAML into a pod - // print our pod and containers, signifying we succeeded - fmt.Printf("Pod:\n%s\n", pod.ID()) - if len(containers) == 1 { - fmt.Printf("Container:\n") - } - if len(containers) > 1 { - fmt.Printf("Containers:\n") - } - for _, ctr := range containers { - fmt.Println(ctr.ID()) - } - - if err := playcleanup(ctx, r, pod, nil); err != nil { - logrus.Errorf("unable to remove pod %s after failing to play kube", pod.ID()) - } - return nil, nil -} - -func playcleanup(ctx context.Context, runtime *LocalRuntime, pod *libpod.Pod, err error) error { - if err != nil && pod != nil { - return runtime.RemovePod(ctx, pod, true, true) - } - return nil -} - -// getPodPorts converts a slice of kube container descriptions to an -// array of ocicni portmapping descriptions usable in libpod -func getPodPorts(containers []v1.Container) []ocicni.PortMapping { - var infraPorts []ocicni.PortMapping - for _, container := range containers { - for _, p := range container.Ports { - if p.HostPort != 0 && p.ContainerPort == 0 { - p.ContainerPort = p.HostPort - } - if p.Protocol == "" { - p.Protocol = "tcp" - } - portBinding := ocicni.PortMapping{ - HostPort: p.HostPort, - ContainerPort: p.ContainerPort, - Protocol: strings.ToLower(string(p.Protocol)), - } - if p.HostIP != "" { - logrus.Debug("HostIP on port bindings is not supported") - } - // only hostPort is utilized in podman context, all container ports - // are accessible inside the shared network namespace - if p.HostPort != 0 { - infraPorts = append(infraPorts, portBinding) - } - - } - } - return infraPorts -} - -func setupSecurityContext(securityConfig *createconfig.SecurityConfig, userConfig *createconfig.UserConfig, containerYAML v1.Container) { - if containerYAML.SecurityContext == nil { - return - } - if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil { - securityConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem - } - if containerYAML.SecurityContext.Privileged != nil { - securityConfig.Privileged = *containerYAML.SecurityContext.Privileged - } - - if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil { - securityConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation - } - - if seopt := containerYAML.SecurityContext.SELinuxOptions; seopt != nil { - if seopt.User != "" { - securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=user:%s", seopt.User)) - securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("user:%s", seopt.User)) - } - if seopt.Role != "" { - securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=role:%s", seopt.Role)) - securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("role:%s", seopt.Role)) - } - if seopt.Type != "" { - securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=type:%s", seopt.Type)) - securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("type:%s", seopt.Type)) - } - if seopt.Level != "" { - securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=level:%s", seopt.Level)) - securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("level:%s", seopt.Level)) - } - } - if caps := containerYAML.SecurityContext.Capabilities; caps != nil { - for _, capability := range caps.Add { - securityConfig.CapAdd = append(securityConfig.CapAdd, string(capability)) - } - for _, capability := range caps.Drop { - securityConfig.CapDrop = append(securityConfig.CapDrop, string(capability)) - } - } - if containerYAML.SecurityContext.RunAsUser != nil { - userConfig.User = fmt.Sprintf("%d", *containerYAML.SecurityContext.RunAsUser) - } - if containerYAML.SecurityContext.RunAsGroup != nil { - if userConfig.User == "" { - userConfig.User = "0" - } - userConfig.User = fmt.Sprintf("%s:%d", userConfig.User, *containerYAML.SecurityContext.RunAsGroup) - } -} - -// kubeContainerToCreateConfig takes a v1.Container and returns a createconfig describing a container -func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, runtime *libpod.Runtime, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID, infraID string, seccompPaths *kubeSeccompPaths) (*createconfig.CreateConfig, error) { - var ( - containerConfig createconfig.CreateConfig - pidConfig createconfig.PidConfig - networkConfig createconfig.NetworkConfig - cgroupConfig createconfig.CgroupConfig - utsConfig createconfig.UtsConfig - ipcConfig createconfig.IpcConfig - userConfig createconfig.UserConfig - securityConfig createconfig.SecurityConfig - ) - - // The default for MemorySwappiness is -1, not 0 - containerConfig.Resources.MemorySwappiness = -1 - - containerConfig.Image = containerYAML.Image - containerConfig.ImageID = newImage.ID() - containerConfig.Name = containerYAML.Name - containerConfig.Tty = containerYAML.TTY - - containerConfig.Pod = podID - - imageData, _ := newImage.Inspect(ctx) - - userConfig.User = "0" - if imageData != nil { - userConfig.User = imageData.Config.User - } - - setupSecurityContext(&securityConfig, &userConfig, containerYAML) - - securityConfig.SeccompProfilePath = seccompPaths.findForContainer(containerConfig.Name) - - containerConfig.Command = []string{} - if imageData != nil && imageData.Config != nil { - containerConfig.Command = append(containerConfig.Command, imageData.Config.Entrypoint...) - } - if len(containerYAML.Command) != 0 { - containerConfig.Command = append(containerConfig.Command, containerYAML.Command...) - } else if imageData != nil && imageData.Config != nil { - containerConfig.Command = append(containerConfig.Command, imageData.Config.Cmd...) - } - if imageData != nil && len(containerConfig.Command) == 0 { - return nil, errors.Errorf("No command specified in container YAML or as CMD or ENTRYPOINT in this image for %s", containerConfig.Name) - } - - containerConfig.UserCommand = containerConfig.Command - - containerConfig.StopSignal = 15 - - containerConfig.WorkDir = "/" - if imageData != nil { - // FIXME, - // we are currently ignoring imageData.Config.ExposedPorts - containerConfig.BuiltinImgVolumes = imageData.Config.Volumes - if imageData.Config.WorkingDir != "" { - containerConfig.WorkDir = imageData.Config.WorkingDir - } - containerConfig.Labels = imageData.Config.Labels - if imageData.Config.StopSignal != "" { - stopSignal, err := util.ParseSignal(imageData.Config.StopSignal) - if err != nil { - return nil, err - } - containerConfig.StopSignal = stopSignal - } - } - - if containerYAML.WorkingDir != "" { - containerConfig.WorkDir = containerYAML.WorkingDir - } - // If the user does not pass in ID mappings, just set to basics - if userConfig.IDMappings == nil { - userConfig.IDMappings = &storage.IDMappingOptions{} - } - - networkConfig.NetMode = ns.NetworkMode(namespaces["net"]) - ipcConfig.IpcMode = ns.IpcMode(namespaces["ipc"]) - utsConfig.UtsMode = ns.UTSMode(namespaces["uts"]) - // disabled in code review per mheon - //containerConfig.PidMode = ns.PidMode(namespaces["pid"]) - userConfig.UsernsMode = ns.UsernsMode(namespaces["user"]) - if len(containerConfig.WorkDir) == 0 { - containerConfig.WorkDir = "/" - } - - containerConfig.Pid = pidConfig - containerConfig.Network = networkConfig - containerConfig.Uts = utsConfig - containerConfig.Ipc = ipcConfig - containerConfig.Cgroup = cgroupConfig - containerConfig.User = userConfig - containerConfig.Security = securityConfig - - annotations := make(map[string]string) - if infraID != "" { - annotations[ann.SandboxID] = infraID - annotations[ann.ContainerType] = ann.ContainerTypeContainer - } - containerConfig.Annotations = annotations - - // Environment Variables - envs := map[string]string{} - if imageData != nil { - imageEnv, err := envLib.ParseSlice(imageData.Config.Env) - if err != nil { - return nil, errors.Wrap(err, "error parsing image environment variables") - } - envs = imageEnv - } - for _, e := range containerYAML.Env { - envs[e.Name] = e.Value - } - containerConfig.Env = envs - - for _, volume := range containerYAML.VolumeMounts { - hostPath, exists := volumes[volume.Name] - if !exists { - return nil, errors.Errorf("Volume mount %s specified for container but not configured in volumes", volume.Name) - } - if err := parse.ValidateVolumeCtrDir(volume.MountPath); err != nil { - return nil, errors.Wrapf(err, "error in parsing MountPath") - } - containerConfig.Volumes = append(containerConfig.Volumes, fmt.Sprintf("%s:%s", hostPath, volume.MountPath)) - } - return &containerConfig, nil -} - -// kubeSeccompPaths holds information about a pod YAML's seccomp configuration -// it holds both container and pod seccomp paths -type kubeSeccompPaths struct { - containerPaths map[string]string - podPath string -} - -// findForContainer checks whether a container has a seccomp path configured for it -// if not, it returns the podPath, which should always have a value -func (k *kubeSeccompPaths) findForContainer(ctrName string) string { - if path, ok := k.containerPaths[ctrName]; ok { - return path - } - return k.podPath -} - -// initializeSeccompPaths takes annotations from the pod object metadata and finds annotations pertaining to seccomp -// it parses both pod and container level -// if the annotation is of the form "localhost/%s", the seccomp profile will be set to profileRoot/%s -func initializeSeccompPaths(annotations map[string]string, profileRoot string) (*kubeSeccompPaths, error) { - seccompPaths := &kubeSeccompPaths{containerPaths: make(map[string]string)} - var err error - if annotations != nil { - for annKeyValue, seccomp := range annotations { - // check if it is prefaced with container.seccomp.security.alpha.kubernetes.io/ - prefixAndCtr := strings.Split(annKeyValue, "/") - if prefixAndCtr[0]+"/" != v1.SeccompContainerAnnotationKeyPrefix { - continue - } else if len(prefixAndCtr) != 2 { - // this could be caused by a user inputting either of - // container.seccomp.security.alpha.kubernetes.io{,/} - // both of which are invalid - return nil, errors.Errorf("Invalid seccomp path: %s", prefixAndCtr[0]) - } - - path, err := verifySeccompPath(seccomp, profileRoot) - if err != nil { - return nil, err - } - seccompPaths.containerPaths[prefixAndCtr[1]] = path - } - - podSeccomp, ok := annotations[v1.SeccompPodAnnotationKey] - if ok { - seccompPaths.podPath, err = verifySeccompPath(podSeccomp, profileRoot) - } else { - seccompPaths.podPath, err = libpod.DefaultSeccompPath() - } - if err != nil { - return nil, err - } - } - return seccompPaths, nil -} - -// verifySeccompPath takes a path and checks whether it is a default, unconfined, or a path -// the available options are parsed as defined in https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp -func verifySeccompPath(path string, profileRoot string) (string, error) { - switch path { - case v1.DeprecatedSeccompProfileDockerDefault: - fallthrough - case v1.SeccompProfileRuntimeDefault: - return libpod.DefaultSeccompPath() - case "unconfined": - return path, nil - default: - parts := strings.Split(path, "/") - if parts[0] == "localhost" { - return filepath.Join(profileRoot, parts[1]), nil - } - return "", errors.Errorf("invalid seccomp path: %s", path) - } -} |