diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/adapter/containers.go | 12 | ||||
-rw-r--r-- | pkg/adapter/pods.go | 101 | ||||
-rw-r--r-- | pkg/adapter/reset.go | 13 | ||||
-rw-r--r-- | pkg/adapter/reset_remote.go | 12 | ||||
-rw-r--r-- | pkg/adapter/runtime.go | 6 | ||||
-rw-r--r-- | pkg/adapter/runtime_remote.go | 71 | ||||
-rw-r--r-- | pkg/adapter/shortcuts/shortcuts.go | 32 | ||||
-rw-r--r-- | pkg/timetype/timestamp.go | 131 | ||||
-rw-r--r-- | pkg/timetype/timestamp_test.go | 95 | ||||
-rw-r--r-- | pkg/varlinkapi/images.go | 10 | ||||
-rw-r--r-- | pkg/varlinkapi/pods.go | 2 | ||||
-rw-r--r-- | pkg/varlinkapi/system.go | 22 |
12 files changed, 444 insertions, 63 deletions
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go index 02da9ec8c..bc9554193 100644 --- a/pkg/adapter/containers.go +++ b/pkg/adapter/containers.go @@ -90,7 +90,7 @@ func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopVa } ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, names, r.Runtime) - if err != nil { + if err != nil && !(cli.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) { return nil, nil, err } @@ -224,7 +224,7 @@ func (r *LocalRuntime) RemoveContainers(ctx context.Context, cli *cliconfig.RmVa } ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, names, r.Runtime) - if err != nil { + if err != nil && !(cli.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) { // Failed to get containers. If force is specified, get the containers ID // and evict them if !cli.Force { @@ -235,6 +235,10 @@ func (r *LocalRuntime) RemoveContainers(ctx context.Context, cli *cliconfig.RmVa logrus.Debugf("Evicting container %q", ctr) id, err := r.EvictContainer(ctx, ctr, cli.Volumes) if err != nil { + if cli.Ignore && errors.Cause(err) == define.ErrNoSuchCtr { + logrus.Debugf("Ignoring error (--allow-missing): %v", err) + continue + } failures[ctr] = errors.Wrapf(err, "Failed to evict container: %q", id) continue } @@ -252,6 +256,10 @@ func (r *LocalRuntime) RemoveContainers(ctx context.Context, cli *cliconfig.RmVa Fn: func() error { err := r.RemoveContainer(ctx, c, cli.Force, cli.Volumes) if err != nil { + if cli.Ignore && errors.Cause(err) == define.ErrNoSuchCtr { + logrus.Debugf("Ignoring error (--allow-missing): %v", err) + return nil + } logrus.Debugf("Failed to remove container %s: %s", c.ID(), err.Error()) } return err diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go index 2003b55ad..a726153c0 100644 --- a/pkg/adapter/pods.go +++ b/pkg/adapter/pods.go @@ -15,6 +15,7 @@ import ( "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" @@ -76,7 +77,7 @@ func (r *LocalRuntime) PrunePods(ctx context.Context, cli *cliconfig.PodPruneVal pool.Add(shared.Job{ ID: p.ID(), Fn: func() error { - err := r.Runtime.RemovePod(ctx, p, cli.Force, cli.Force) + err := r.Runtime.RemovePod(ctx, p, true, cli.Force) if err != nil { logrus.Debugf("Failed to remove pod %s: %s", p.ID(), err.Error()) } @@ -94,13 +95,13 @@ func (r *LocalRuntime) RemovePods(ctx context.Context, cli *cliconfig.PodRmValue podids []string ) pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime) - if err != nil { + 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, cli.Force, cli.Force); err != nil { + if err := r.Runtime.RemovePod(ctx, p, true, cli.Force); err != nil { errs = append(errs, err) } else { podids = append(podids, p.ID()) @@ -151,7 +152,7 @@ func (r *LocalRuntime) StopPods(ctx context.Context, cli *cliconfig.PodStopValue podids []string ) pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime) - if err != nil { + if err != nil && !(cli.Ignore && errors.Cause(err) == define.ErrNoSuchPod) { errs = append(errs, err) return nil, errs } @@ -596,12 +597,17 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa volumes[volume.Name] = hostPath.Path } + seccompPaths, err := initializeSeccompPaths(podYAML.ObjectMeta.Annotations) + if err != nil { + return nil, err + } + for _, container := range podYAML.Spec.Containers { newImage, err := r.ImageRuntime().New(ctx, container.Image, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageMissing) if err != nil { return nil, err } - createConfig, err := kubeContainerToCreateConfig(ctx, container, r.Runtime, newImage, namespaces, volumes, pod.ID(), podInfraID) + createConfig, err := kubeContainerToCreateConfig(ctx, container, r.Runtime, newImage, namespaces, volumes, pod.ID(), podInfraID, seccompPaths) if err != nil { return nil, err } @@ -720,7 +726,7 @@ func setupSecurityContext(securityConfig *createconfig.SecurityConfig, userConfi } // 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) (*createconfig.CreateConfig, error) { +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 @@ -752,11 +758,7 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container setupSecurityContext(&securityConfig, &userConfig, containerYAML) - var err error - containerConfig.Security.SeccompProfilePath, err = libpod.DefaultSeccompPath() - if err != nil { - return nil, err - } + securityConfig.SeccompProfilePath = seccompPaths.findForContainer(containerConfig.Name) containerConfig.Command = []string{} if imageData != nil && imageData.Config != nil { @@ -826,3 +828,80 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container } 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 +func initializeSeccompPaths(annotations map[string]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) + if err != nil { + return nil, err + } + seccompPaths.containerPaths[prefixAndCtr[1]] = path + } + + podSeccomp, ok := annotations[v1.SeccompPodAnnotationKey] + if ok { + seccompPaths.podPath, err = verifySeccompPath(podSeccomp) + } 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) (string, error) { + switch path { + case v1.DeprecatedSeccompProfileDockerDefault: + fallthrough + case v1.SeccompProfileRuntimeDefault: + return libpod.DefaultSeccompPath() + case "unconfined": + return path, nil + default: + // TODO we have an inconsistency here + // k8s parses `localhost/<path>` which is found at `<seccomp_root>` + // we currently parse `localhost:<seccomp_root>/<path> + // to fully conform, we need to find a good location for the seccomp root + parts := strings.Split(path, ":") + if parts[0] == "localhost" { + return parts[1], nil + } + return "", errors.Errorf("invalid seccomp path: %s", path) + } +} diff --git a/pkg/adapter/reset.go b/pkg/adapter/reset.go new file mode 100644 index 000000000..0decc3d15 --- /dev/null +++ b/pkg/adapter/reset.go @@ -0,0 +1,13 @@ +// +build !remoteclient + +package adapter + +import ( + "context" +) + +// Reset the container storage back to initial states. +// Removes all Pods, Containers, Images and Volumes. +func (r *LocalRuntime) Reset() error { + return r.Runtime.Reset(context.TODO()) +} diff --git a/pkg/adapter/reset_remote.go b/pkg/adapter/reset_remote.go new file mode 100644 index 000000000..663fab639 --- /dev/null +++ b/pkg/adapter/reset_remote.go @@ -0,0 +1,12 @@ +// +build remoteclient + +package adapter + +import ( + "github.com/containers/libpod/cmd/podman/varlink" +) + +// Info returns information for the host system and its components +func (r RemoteRuntime) Reset() error { + return iopodman.Reset().Call(r.Conn) +} diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go index 81a43853c..069283bde 100644 --- a/pkg/adapter/runtime.go +++ b/pkg/adapter/runtime.go @@ -27,7 +27,7 @@ import ( "github.com/containers/libpod/pkg/util" "github.com/containers/storage/pkg/archive" "github.com/pkg/errors" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" ) // LocalRuntime describes a typical libpod runtime @@ -147,8 +147,8 @@ func (r *LocalRuntime) RemoveImage(ctx context.Context, img *ContainerImage, for } // PruneImages is wrapper into PruneImages within the image pkg -func (r *LocalRuntime) PruneImages(ctx context.Context, all bool) ([]string, error) { - return r.ImageRuntime().PruneImages(ctx, all) +func (r *LocalRuntime) PruneImages(ctx context.Context, all bool, filter []string) ([]string, error) { + return r.ImageRuntime().PruneImages(ctx, all, filter) } // Export is a wrapper to container export to a tarfile diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go index 01bc8e454..f9232897c 100644 --- a/pkg/adapter/runtime_remote.go +++ b/pkg/adapter/runtime_remote.go @@ -136,21 +136,22 @@ type ContainerImage struct { } type remoteImage struct { - ID string - Labels map[string]string - RepoTags []string - RepoDigests []string - Parent string - Size int64 - Created time.Time - InputName string - Names []string - Digest digest.Digest - Digests []digest.Digest - isParent bool - Runtime *LocalRuntime - TopLayer string - ReadOnly bool + ID string + Labels map[string]string + RepoTags []string + RepoDigests []string + Parent string + Size int64 + Created time.Time + InputName string + Names []string + Digest digest.Digest + Digests []digest.Digest + isParent bool + Runtime *LocalRuntime + TopLayer string + ReadOnly bool + NamesHistory []string } // Container ... @@ -232,21 +233,22 @@ func imageInListToContainerImage(i iopodman.Image, name string, runtime *LocalRu digests = append(digests, digest.Digest(d)) } ri := remoteImage{ - InputName: name, - ID: i.Id, - Digest: digest.Digest(i.Digest), - Digests: digests, - Labels: i.Labels, - RepoTags: i.RepoTags, - RepoDigests: i.RepoTags, - Parent: i.ParentId, - Size: i.Size, - Created: created, - Names: i.RepoTags, - isParent: i.IsParent, - Runtime: runtime, - TopLayer: i.TopLayer, - ReadOnly: i.ReadOnly, + InputName: name, + ID: i.Id, + Digest: digest.Digest(i.Digest), + Digests: digests, + Labels: i.Labels, + RepoTags: i.RepoTags, + RepoDigests: i.RepoTags, + Parent: i.ParentId, + Size: i.Size, + Created: created, + Names: i.RepoTags, + isParent: i.IsParent, + Runtime: runtime, + TopLayer: i.TopLayer, + ReadOnly: i.ReadOnly, + NamesHistory: i.History, } return &ContainerImage{ri}, nil } @@ -337,6 +339,11 @@ func (ci *ContainerImage) Names() []string { return ci.remoteImage.Names } +// NamesHistory returns a string array of names previously associated with the image +func (ci *ContainerImage) NamesHistory() []string { + return ci.remoteImage.NamesHistory +} + // Created returns the time the image was created func (ci *ContainerImage) Created() time.Time { return ci.remoteImage.Created @@ -415,8 +422,8 @@ func (ci *ContainerImage) History(ctx context.Context) ([]*image.History, error) } // PruneImages is the wrapper call for a remote-client to prune images -func (r *LocalRuntime) PruneImages(ctx context.Context, all bool) ([]string, error) { - return iopodman.ImagesPrune().Call(r.Conn, all) +func (r *LocalRuntime) PruneImages(ctx context.Context, all bool, filter []string) ([]string, error) { + return iopodman.ImagesPrune().Call(r.Conn, all, filter) } // Export is a wrapper to container export to a tarfile diff --git a/pkg/adapter/shortcuts/shortcuts.go b/pkg/adapter/shortcuts/shortcuts.go index 3e4eff555..4f6cfd6a3 100644 --- a/pkg/adapter/shortcuts/shortcuts.go +++ b/pkg/adapter/shortcuts/shortcuts.go @@ -2,9 +2,11 @@ package shortcuts import ( "github.com/containers/libpod/libpod" + "github.com/sirupsen/logrus" ) -// GetPodsByContext gets pods whether all, latest, or a slice of names/ids +// GetPodsByContext returns a slice of pods. Note that all, latest and pods are +// mutually exclusive arguments. func GetPodsByContext(all, latest bool, pods []string, runtime *libpod.Runtime) ([]*libpod.Pod, error) { var outpods []*libpod.Pod if all { @@ -18,17 +20,24 @@ func GetPodsByContext(all, latest bool, pods []string, runtime *libpod.Runtime) outpods = append(outpods, p) return outpods, nil } + var err error for _, p := range pods { - pod, err := runtime.LookupPod(p) - if err != nil { - return nil, err + pod, e := runtime.LookupPod(p) + if e != nil { + // Log all errors here, so callers don't need to. + logrus.Debugf("Error looking up pod %q: %v", p, e) + if err == nil { + err = e + } + } else { + outpods = append(outpods, pod) } - outpods = append(outpods, pod) } - return outpods, nil + return outpods, err } // GetContainersByContext gets pods whether all, latest, or a slice of names/ids +// is specified. func GetContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, err error) { var ctr *libpod.Container ctrs = []*libpod.Container{} @@ -41,10 +50,15 @@ func GetContainersByContext(all, latest bool, names []string, runtime *libpod.Ru } else { for _, n := range names { ctr, e := runtime.LookupContainer(n) - if e != nil && err == nil { - err = e + if e != nil { + // Log all errors here, so callers don't need to. + logrus.Debugf("Error looking up container %q: %v", n, e) + if err == nil { + err = e + } + } else { + ctrs = append(ctrs, ctr) } - ctrs = append(ctrs, ctr) } } return diff --git a/pkg/timetype/timestamp.go b/pkg/timetype/timestamp.go new file mode 100644 index 000000000..eb904a574 --- /dev/null +++ b/pkg/timetype/timestamp.go @@ -0,0 +1,131 @@ +package timetype + +// code adapted from https://github.com/moby/moby/blob/master/api/types/time/timestamp.go + +import ( + "fmt" + "math" + "strconv" + "strings" + "time" +) + +// These are additional predefined layouts for use in Time.Format and Time.Parse +// with --since and --until parameters for `docker logs` and `docker events` +const ( + rFC3339Local = "2006-01-02T15:04:05" // RFC3339 with local timezone + rFC3339NanoLocal = "2006-01-02T15:04:05.999999999" // RFC3339Nano with local timezone + dateWithZone = "2006-01-02Z07:00" // RFC3339 with time at 00:00:00 + dateLocal = "2006-01-02" // RFC3339 with local timezone and time at 00:00:00 +) + +// GetTimestamp tries to parse given string as golang duration, +// then RFC3339 time and finally as a Unix timestamp. If +// any of these were successful, it returns a Unix timestamp +// as string otherwise returns the given value back. +// In case of duration input, the returned timestamp is computed +// as the given reference time minus the amount of the duration. +func GetTimestamp(value string, reference time.Time) (string, error) { + if d, err := time.ParseDuration(value); value != "0" && err == nil { + return strconv.FormatInt(reference.Add(-d).Unix(), 10), nil + } + + var format string + // if the string has a Z or a + or three dashes use parse otherwise use parseinlocation + parseInLocation := !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3) + + if strings.Contains(value, ".") { + if parseInLocation { + format = rFC3339NanoLocal + } else { + format = time.RFC3339Nano + } + } else if strings.Contains(value, "T") { + // we want the number of colons in the T portion of the timestamp + tcolons := strings.Count(value, ":") + // if parseInLocation is off and we have a +/- zone offset (not Z) then + // there will be an extra colon in the input for the tz offset subtract that + // colon from the tcolons count + if !parseInLocation && !strings.ContainsAny(value, "zZ") && tcolons > 0 { + tcolons-- + } + if parseInLocation { + switch tcolons { + case 0: + format = "2006-01-02T15" + case 1: + format = "2006-01-02T15:04" + default: + format = rFC3339Local + } + } else { + switch tcolons { + case 0: + format = "2006-01-02T15Z07:00" + case 1: + format = "2006-01-02T15:04Z07:00" + default: + format = time.RFC3339 + } + } + } else if parseInLocation { + format = dateLocal + } else { + format = dateWithZone + } + + var t time.Time + var err error + + if parseInLocation { + t, err = time.ParseInLocation(format, value, time.FixedZone(reference.Zone())) + } else { + t, err = time.Parse(format, value) + } + + if err != nil { + // if there is a `-` then it's an RFC3339 like timestamp + if strings.Contains(value, "-") { + return "", err // was probably an RFC3339 like timestamp but the parser failed with an error + } + if _, _, err := parseTimestamp(value); err != nil { + return "", fmt.Errorf("failed to parse value as time or duration: %q", value) + } + return value, nil // unix timestamp in and out case (meaning: the value passed at the command line is already in the right format for passing to the server) + } + + return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())), nil +} + +// ParseTimestamps returns seconds and nanoseconds from a timestamp that has the +// format "%d.%09d", time.Unix(), int64(time.Nanosecond())) +// if the incoming nanosecond portion is longer or shorter than 9 digits it is +// converted to nanoseconds. The expectation is that the seconds and +// seconds will be used to create a time variable. For example: +// seconds, nanoseconds, err := ParseTimestamp("1136073600.000000001",0) +// if err == nil since := time.Unix(seconds, nanoseconds) +// returns seconds as def(aultSeconds) if value == "" +func ParseTimestamps(value string, def int64) (int64, int64, error) { + if value == "" { + return def, 0, nil + } + return parseTimestamp(value) +} + +func parseTimestamp(value string) (int64, int64, error) { + sa := strings.SplitN(value, ".", 2) + s, err := strconv.ParseInt(sa[0], 10, 64) + if err != nil { + return s, 0, err + } + if len(sa) != 2 { + return s, 0, nil + } + n, err := strconv.ParseInt(sa[1], 10, 64) + if err != nil { + return s, n, err + } + // should already be in nanoseconds but just in case convert n to nanoseconds + n = int64(float64(n) * math.Pow(float64(10), float64(9-len(sa[1])))) + return s, n, nil +} diff --git a/pkg/timetype/timestamp_test.go b/pkg/timetype/timestamp_test.go new file mode 100644 index 000000000..0fffb85a9 --- /dev/null +++ b/pkg/timetype/timestamp_test.go @@ -0,0 +1,95 @@ +package timetype + +// code adapted from https://github.com/moby/moby/blob/master/api/types/time/timestamp.go + +import ( + "fmt" + "testing" + "time" +) + +func TestGetTimestamp(t *testing.T) { + now := time.Now().In(time.UTC) + cases := []struct { + in, expected string + expectedErr bool + }{ + // Partial RFC3339 strings get parsed with second precision + {"2006-01-02T15:04:05.999999999+07:00", "1136189045.999999999", false}, + {"2006-01-02T15:04:05.999999999Z", "1136214245.999999999", false}, + {"2006-01-02T15:04:05.999999999", "1136214245.999999999", false}, + {"2006-01-02T15:04:05Z", "1136214245.000000000", false}, + {"2006-01-02T15:04:05", "1136214245.000000000", false}, + {"2006-01-02T15:04:0Z", "", true}, + {"2006-01-02T15:04:0", "", true}, + {"2006-01-02T15:04Z", "1136214240.000000000", false}, + {"2006-01-02T15:04+00:00", "1136214240.000000000", false}, + {"2006-01-02T15:04-00:00", "1136214240.000000000", false}, + {"2006-01-02T15:04", "1136214240.000000000", false}, + {"2006-01-02T15:0Z", "", true}, + {"2006-01-02T15:0", "", true}, + {"2006-01-02T15Z", "1136214000.000000000", false}, + {"2006-01-02T15+00:00", "1136214000.000000000", false}, + {"2006-01-02T15-00:00", "1136214000.000000000", false}, + {"2006-01-02T15", "1136214000.000000000", false}, + {"2006-01-02T1Z", "1136163600.000000000", false}, + {"2006-01-02T1", "1136163600.000000000", false}, + {"2006-01-02TZ", "", true}, + {"2006-01-02T", "", true}, + {"2006-01-02+00:00", "1136160000.000000000", false}, + {"2006-01-02-00:00", "1136160000.000000000", false}, + {"2006-01-02-00:01", "1136160060.000000000", false}, + {"2006-01-02Z", "1136160000.000000000", false}, + {"2006-01-02", "1136160000.000000000", false}, + {"2015-05-13T20:39:09Z", "1431549549.000000000", false}, + + // unix timestamps returned as is + {"1136073600", "1136073600", false}, + {"1136073600.000000001", "1136073600.000000001", false}, + // Durations + {"1m", fmt.Sprintf("%d", now.Add(-1*time.Minute).Unix()), false}, + {"1.5h", fmt.Sprintf("%d", now.Add(-90*time.Minute).Unix()), false}, + {"1h30m", fmt.Sprintf("%d", now.Add(-90*time.Minute).Unix()), false}, + + {"invalid", "", true}, + {"", "", true}, + } + + for _, c := range cases { + o, err := GetTimestamp(c.in, now) + if o != c.expected || + (err == nil && c.expectedErr) || + (err != nil && !c.expectedErr) { + t.Errorf("wrong value for '%s'. expected:'%s' got:'%s' with error: `%s`", c.in, c.expected, o, err) + t.Fail() + } + } +} + +func TestParseTimestamps(t *testing.T) { + cases := []struct { + in string + def, expectedS, expectedN int64 + expectedErr bool + }{ + // unix timestamps + {"1136073600", 0, 1136073600, 0, false}, + {"1136073600.000000001", 0, 1136073600, 1, false}, + {"1136073600.0000000010", 0, 1136073600, 1, false}, + {"1136073600.00000001", 0, 1136073600, 10, false}, + {"foo.bar", 0, 0, 0, true}, + {"1136073600.bar", 0, 1136073600, 0, true}, + {"", -1, -1, 0, false}, + } + + for _, c := range cases { + s, n, err := ParseTimestamps(c.in, c.def) + if s != c.expectedS || + n != c.expectedN || + (err == nil && c.expectedErr) || + (err != nil && !c.expectedErr) { + t.Errorf("wrong values for input `%s` with default `%d` expected:'%d'seconds and `%d`nanosecond got:'%d'seconds and `%d`nanoseconds with error: `%s`", c.in, c.def, c.expectedS, c.expectedN, s, n, err) + t.Fail() + } + } +} diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go index 8d44e6373..7abffa42a 100644 --- a/pkg/varlinkapi/images.go +++ b/pkg/varlinkapi/images.go @@ -21,7 +21,7 @@ import ( "github.com/containers/image/v5/transports/alltransports" "github.com/containers/image/v5/types" "github.com/containers/libpod/cmd/podman/shared" - "github.com/containers/libpod/cmd/podman/varlink" + iopodman "github.com/containers/libpod/cmd/podman/varlink" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/image" @@ -29,7 +29,7 @@ import ( "github.com/containers/libpod/pkg/util" "github.com/containers/libpod/utils" "github.com/containers/storage/pkg/archive" - "github.com/opencontainers/image-spec/specs-go/v1" + v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -70,6 +70,7 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error { Labels: labels, IsParent: isParent, ReadOnly: image.IsReadOnly(), + History: image.NamesHistory(), } imageList = append(imageList, i) } @@ -111,6 +112,7 @@ func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, id string) error { Labels: labels, TopLayer: newImage.TopLayer(), ReadOnly: newImage.IsReadOnly(), + History: newImage.NamesHistory(), } return call.ReplyGetImage(il) } @@ -740,8 +742,8 @@ func (i *LibpodAPI) ContainerRunlabel(call iopodman.VarlinkCall, input iopodman. } // ImagesPrune .... -func (i *LibpodAPI) ImagesPrune(call iopodman.VarlinkCall, all bool) error { - prunedImages, err := i.Runtime.ImageRuntime().PruneImages(context.TODO(), all) +func (i *LibpodAPI) ImagesPrune(call iopodman.VarlinkCall, all bool, filter []string) error { + prunedImages, err := i.Runtime.ImageRuntime().PruneImages(context.TODO(), all, []string{}) if err != nil { return call.ReplyErrorOccurred(err.Error()) } diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go index 9b659f66b..1ebe5d424 100644 --- a/pkg/varlinkapi/pods.go +++ b/pkg/varlinkapi/pods.go @@ -247,7 +247,7 @@ func (i *LibpodAPI) RemovePod(call iopodman.VarlinkCall, name string, force bool if err != nil { return call.ReplyPodNotFound(name, err.Error()) } - if err = i.Runtime.RemovePod(ctx, pod, force, force); err != nil { + if err = i.Runtime.RemovePod(ctx, pod, true, force); err != nil { return call.ReplyErrorOccurred(err.Error()) } diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go index f6057f5fc..b81ff11ba 100644 --- a/pkg/varlinkapi/system.go +++ b/pkg/varlinkapi/system.go @@ -3,12 +3,15 @@ package varlinkapi import ( + "context" "fmt" - "github.com/containers/libpod/libpod/define" + "os" goruntime "runtime" "time" "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/libpod/define" + "github.com/sirupsen/logrus" ) // GetVersion ... @@ -105,3 +108,20 @@ func (i *LibpodAPI) GetInfo(call iopodman.VarlinkCall) error { podmanInfo.Insecure_registries = insecureRegistries return call.ReplyGetInfo(podmanInfo) } + +// GetVersion ... +func (i *LibpodAPI) Reset(call iopodman.VarlinkCall) error { + if err := i.Runtime.Reset(context.TODO()); err != nil { + logrus.Errorf("Reset Failed: %v", err) + if err := call.ReplyErrorOccurred(err.Error()); err != nil { + logrus.Errorf("Failed to send ReplyErrorOccurred: %v", err) + } + os.Exit(define.ExecErrorCodeGeneric) + } + if err := call.ReplyReset(); err != nil { + logrus.Errorf("Failed to send ReplyReset: %v", err) + os.Exit(define.ExecErrorCodeGeneric) + } + os.Exit(0) + return nil +} |