2017-05-20 02:13:15 +08:00
|
|
|
package util
|
|
|
|
|
|
|
|
import (
|
2018-06-15 06:39:19 +08:00
|
|
|
"bufio"
|
2018-04-07 08:11:17 +08:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2018-01-23 23:27:32 +08:00
|
|
|
"net/url"
|
2018-06-13 05:21:08 +08:00
|
|
|
"os"
|
2017-06-29 05:07:58 +08:00
|
|
|
"path"
|
2018-06-15 06:39:19 +08:00
|
|
|
"strconv"
|
2017-06-29 05:07:58 +08:00
|
|
|
"strings"
|
2019-01-09 05:57:49 +08:00
|
|
|
"syscall"
|
2017-06-29 05:07:58 +08:00
|
|
|
|
2017-05-20 02:13:15 +08:00
|
|
|
"github.com/containers/image/docker/reference"
|
2018-08-03 04:55:17 +08:00
|
|
|
"github.com/containers/image/pkg/sysregistriesv2"
|
2018-06-29 01:59:42 +08:00
|
|
|
"github.com/containers/image/signature"
|
2017-05-20 02:13:15 +08:00
|
|
|
is "github.com/containers/image/storage"
|
2019-02-02 20:29:05 +08:00
|
|
|
"github.com/containers/image/transports"
|
2017-06-29 05:07:58 +08:00
|
|
|
"github.com/containers/image/types"
|
2017-05-20 02:13:15 +08:00
|
|
|
"github.com/containers/storage"
|
2018-06-15 06:39:19 +08:00
|
|
|
"github.com/containers/storage/pkg/idtools"
|
2018-01-23 23:27:32 +08:00
|
|
|
"github.com/docker/distribution/registry/api/errcode"
|
2019-02-22 06:08:48 +08:00
|
|
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
2017-06-02 03:23:02 +08:00
|
|
|
"github.com/pkg/errors"
|
2017-06-29 05:07:58 +08:00
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
minimumTruncatedIDLength = 3
|
2018-10-20 05:24:49 +08:00
|
|
|
// DefaultTransport is a prefix that we apply to an image name if we
|
|
|
|
// can't find one in the local Store, in order to generate a source
|
|
|
|
// reference for the image that we can then copy to the local Store.
|
|
|
|
DefaultTransport = "docker://"
|
2017-06-29 05:07:58 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// RegistryDefaultPathPrefix contains a per-registry listing of default prefixes
|
|
|
|
// to prepend to image names that only contain a single path component.
|
|
|
|
RegistryDefaultPathPrefix = map[string]string{
|
|
|
|
"index.docker.io": "library",
|
|
|
|
"docker.io": "library",
|
|
|
|
}
|
2017-05-20 02:13:15 +08:00
|
|
|
)
|
|
|
|
|
2018-05-02 03:37:13 +08:00
|
|
|
// ResolveName checks if name is a valid image name, and if that name doesn't
|
|
|
|
// include a domain portion, returns a list of the names which it might
|
2019-02-02 20:29:05 +08:00
|
|
|
// correspond to in the set of configured registries, the transport used to
|
|
|
|
// pull the image, and a boolean which is true iff
|
|
|
|
// 1) the list of search registries was used, and 2) it was empty.
|
2019-02-22 06:08:48 +08:00
|
|
|
//
|
|
|
|
// The returned image names never include a transport: prefix, and if transport != "",
|
|
|
|
// (transport, image) should be a valid input to alltransports.ParseImageName.
|
|
|
|
//
|
2018-08-04 09:21:57 +08:00
|
|
|
// NOTE: The "list of search registries is empty" check does not count blocked registries,
|
|
|
|
// and neither the implied "localhost" nor a possible firstRegistry are counted
|
2019-02-02 20:29:05 +08:00
|
|
|
func ResolveName(name string, firstRegistry string, sc *types.SystemContext, store storage.Store) ([]string, string, bool, error) {
|
2017-06-29 05:07:58 +08:00
|
|
|
if name == "" {
|
2019-02-02 20:29:05 +08:00
|
|
|
return nil, "", false, nil
|
2017-06-29 05:07:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Maybe it's a truncated image ID. Don't prepend a registry name, then.
|
|
|
|
if len(name) >= minimumTruncatedIDLength {
|
|
|
|
if img, err := store.Image(name); err == nil && img != nil && strings.HasPrefix(img.ID, name) {
|
|
|
|
// It's a truncated version of the ID of an image that's present in local storage;
|
2018-08-22 04:33:36 +08:00
|
|
|
// we need only expand the ID.
|
2019-02-02 20:29:05 +08:00
|
|
|
return []string{img.ID}, "", false, nil
|
2017-06-29 05:07:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-19 04:09:01 +08:00
|
|
|
// If the image includes a transport's name as a prefix, use it as-is.
|
2019-02-02 20:29:05 +08:00
|
|
|
if strings.HasPrefix(name, DefaultTransport) {
|
|
|
|
return []string{strings.TrimPrefix(name, DefaultTransport)}, DefaultTransport, false, nil
|
|
|
|
}
|
2018-03-19 10:16:47 +08:00
|
|
|
split := strings.SplitN(name, ":", 2)
|
|
|
|
if len(split) == 2 {
|
2019-02-02 20:29:05 +08:00
|
|
|
if trans := transports.Get(split[0]); trans != nil {
|
|
|
|
return []string{split[1]}, trans.Name(), false, nil
|
2018-03-19 10:16:47 +08:00
|
|
|
}
|
|
|
|
}
|
2017-06-29 05:07:58 +08:00
|
|
|
// If the image name already included a domain component, we're done.
|
|
|
|
named, err := reference.ParseNormalizedNamed(name)
|
|
|
|
if err != nil {
|
2019-02-02 20:29:05 +08:00
|
|
|
return nil, "", false, errors.Wrapf(err, "error parsing image name %q", name)
|
2017-06-29 05:07:58 +08:00
|
|
|
}
|
|
|
|
if named.String() == name {
|
|
|
|
// Parsing produced the same result, so there was a domain name in there to begin with.
|
2019-02-02 20:29:05 +08:00
|
|
|
return []string{name}, DefaultTransport, false, nil
|
2017-06-29 05:07:58 +08:00
|
|
|
}
|
|
|
|
if reference.Domain(named) != "" && RegistryDefaultPathPrefix[reference.Domain(named)] != "" {
|
|
|
|
// If this domain can cause us to insert something in the middle, check if that happened.
|
|
|
|
repoPath := reference.Path(named)
|
|
|
|
domain := reference.Domain(named)
|
2018-05-19 04:09:01 +08:00
|
|
|
tag := ""
|
|
|
|
if tagged, ok := named.(reference.Tagged); ok {
|
|
|
|
tag = ":" + tagged.Tag()
|
|
|
|
}
|
|
|
|
digest := ""
|
|
|
|
if digested, ok := named.(reference.Digested); ok {
|
|
|
|
digest = "@" + digested.Digest().String()
|
|
|
|
}
|
2017-06-29 05:07:58 +08:00
|
|
|
defaultPrefix := RegistryDefaultPathPrefix[reference.Domain(named)] + "/"
|
2018-05-19 04:09:01 +08:00
|
|
|
if strings.HasPrefix(repoPath, defaultPrefix) && path.Join(domain, repoPath[len(defaultPrefix):])+tag+digest == name {
|
2017-06-29 05:07:58 +08:00
|
|
|
// Yup, parsing just inserted a bit in the middle, so there was a domain name there to begin with.
|
2019-02-02 20:29:05 +08:00
|
|
|
return []string{name}, DefaultTransport, false, nil
|
2017-06-29 05:07:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Figure out the list of registries.
|
2018-08-03 04:55:17 +08:00
|
|
|
var registries []string
|
2018-12-04 02:02:47 +08:00
|
|
|
searchRegistries, err := sysregistriesv2.FindUnqualifiedSearchRegistries(sc)
|
2017-06-29 05:07:58 +08:00
|
|
|
if err != nil {
|
2018-05-02 03:37:13 +08:00
|
|
|
logrus.Debugf("unable to read configured registries to complete %q: %v", name, err)
|
2017-06-29 05:07:58 +08:00
|
|
|
}
|
2018-12-04 02:02:47 +08:00
|
|
|
for _, registry := range searchRegistries {
|
2018-08-03 04:55:17 +08:00
|
|
|
if !registry.Blocked {
|
|
|
|
registries = append(registries, registry.URL)
|
|
|
|
}
|
|
|
|
}
|
2018-08-04 09:21:57 +08:00
|
|
|
searchRegistriesAreEmpty := len(registries) == 0
|
2017-06-29 05:07:58 +08:00
|
|
|
|
|
|
|
// Create all of the combinations. Some registries need an additional component added, so
|
2018-05-02 03:37:13 +08:00
|
|
|
// use our lookaside map to keep track of them. If there are no configured registries, we'll
|
|
|
|
// return a name using "localhost" as the registry name.
|
2017-06-29 05:07:58 +08:00
|
|
|
candidates := []string{}
|
2018-05-02 03:37:13 +08:00
|
|
|
initRegistries := []string{"localhost"}
|
|
|
|
if firstRegistry != "" && firstRegistry != "localhost" {
|
|
|
|
initRegistries = append([]string{firstRegistry}, initRegistries...)
|
|
|
|
}
|
|
|
|
for _, registry := range append(initRegistries, registries...) {
|
2017-06-29 05:07:58 +08:00
|
|
|
if registry == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
middle := ""
|
|
|
|
if prefix, ok := RegistryDefaultPathPrefix[registry]; ok && strings.IndexRune(name, '/') == -1 {
|
|
|
|
middle = prefix
|
|
|
|
}
|
|
|
|
candidate := path.Join(registry, middle, name)
|
|
|
|
candidates = append(candidates, candidate)
|
|
|
|
}
|
2019-02-02 20:29:05 +08:00
|
|
|
return candidates, DefaultTransport, searchRegistriesAreEmpty, nil
|
2017-06-29 05:07:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// ExpandNames takes unqualified names, parses them as image names, and returns
|
|
|
|
// the fully expanded result, including a tag. Names which don't include a registry
|
|
|
|
// name will be marked for the most-preferred registry (i.e., the first one in our
|
|
|
|
// configuration).
|
2018-05-02 03:37:13 +08:00
|
|
|
func ExpandNames(names []string, firstRegistry string, systemContext *types.SystemContext, store storage.Store) ([]string, error) {
|
2017-06-29 05:07:58 +08:00
|
|
|
expanded := make([]string, 0, len(names))
|
|
|
|
for _, n := range names {
|
2018-05-02 03:37:13 +08:00
|
|
|
var name reference.Named
|
2019-02-02 20:29:05 +08:00
|
|
|
nameList, _, _, err := ResolveName(n, firstRegistry, systemContext, store)
|
2018-08-22 04:33:36 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error parsing name %q", n)
|
|
|
|
}
|
2018-05-02 03:37:13 +08:00
|
|
|
if len(nameList) == 0 {
|
|
|
|
named, err := reference.ParseNormalizedNamed(n)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error parsing name %q", n)
|
|
|
|
}
|
|
|
|
name = named
|
|
|
|
} else {
|
|
|
|
named, err := reference.ParseNormalizedNamed(nameList[0])
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error parsing name %q", nameList[0])
|
|
|
|
}
|
|
|
|
name = named
|
2017-05-20 02:13:15 +08:00
|
|
|
}
|
|
|
|
name = reference.TagNameOnly(name)
|
2017-06-29 05:07:58 +08:00
|
|
|
tag := ""
|
|
|
|
digest := ""
|
2017-05-20 02:13:15 +08:00
|
|
|
if tagged, ok := name.(reference.NamedTagged); ok {
|
|
|
|
tag = ":" + tagged.Tag()
|
|
|
|
}
|
2017-06-29 05:07:58 +08:00
|
|
|
if digested, ok := name.(reference.Digested); ok {
|
|
|
|
digest = "@" + digested.Digest().String()
|
|
|
|
}
|
|
|
|
expanded = append(expanded, name.Name()+tag+digest)
|
2017-05-20 02:13:15 +08:00
|
|
|
}
|
|
|
|
return expanded, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// FindImage locates the locally-stored image which corresponds to a given name.
|
2018-05-02 03:37:13 +08:00
|
|
|
func FindImage(store storage.Store, firstRegistry string, systemContext *types.SystemContext, image string) (types.ImageReference, *storage.Image, error) {
|
|
|
|
var ref types.ImageReference
|
2017-06-07 21:39:33 +08:00
|
|
|
var img *storage.Image
|
2018-05-02 03:37:13 +08:00
|
|
|
var err error
|
2019-02-02 20:29:05 +08:00
|
|
|
names, _, _, err := ResolveName(image, firstRegistry, systemContext, store)
|
2018-08-22 04:33:36 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, errors.Wrapf(err, "error parsing name %q", image)
|
|
|
|
}
|
|
|
|
for _, name := range names {
|
2018-05-02 03:37:13 +08:00
|
|
|
ref, err = is.Transport.ParseStoreReference(store, name)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Debugf("error parsing reference to image %q: %v", name, err)
|
|
|
|
continue
|
|
|
|
}
|
2017-06-07 21:39:33 +08:00
|
|
|
img, err = is.Transport.GetStoreImage(store, ref)
|
2018-05-02 03:37:13 +08:00
|
|
|
if err != nil {
|
|
|
|
img2, err2 := store.Image(name)
|
|
|
|
if err2 != nil {
|
|
|
|
logrus.Debugf("error locating image %q: %v", name, err2)
|
|
|
|
continue
|
2017-06-07 21:39:33 +08:00
|
|
|
}
|
2018-05-02 03:37:13 +08:00
|
|
|
img = img2
|
2017-06-07 21:39:33 +08:00
|
|
|
}
|
2018-05-02 03:37:13 +08:00
|
|
|
break
|
|
|
|
}
|
|
|
|
if ref == nil || img == nil {
|
|
|
|
return nil, nil, errors.Wrapf(err, "error locating image with name %q", image)
|
2017-05-20 02:13:15 +08:00
|
|
|
}
|
2018-05-02 03:37:13 +08:00
|
|
|
return ref, img, nil
|
2017-05-20 02:13:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// AddImageNames adds the specified names to the specified image.
|
2018-05-02 03:37:13 +08:00
|
|
|
func AddImageNames(store storage.Store, firstRegistry string, systemContext *types.SystemContext, image *storage.Image, addNames []string) error {
|
|
|
|
names, err := ExpandNames(addNames, firstRegistry, systemContext, store)
|
2017-05-20 02:13:15 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = store.SetNames(image.ID, append(image.Names, names...))
|
|
|
|
if err != nil {
|
2017-06-02 03:23:02 +08:00
|
|
|
return errors.Wrapf(err, "error adding names (%v) to image %q", names, image.ID)
|
2017-05-20 02:13:15 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2018-01-23 23:27:32 +08:00
|
|
|
|
|
|
|
// GetFailureCause checks the type of the error "err" and returns a new
|
|
|
|
// error message that reflects the reason of the failure.
|
|
|
|
// In case err type is not a familiar one the error "defaultError" is returned.
|
|
|
|
func GetFailureCause(err, defaultError error) error {
|
|
|
|
switch nErr := errors.Cause(err).(type) {
|
|
|
|
case errcode.Errors:
|
2018-02-18 08:21:14 +08:00
|
|
|
return err
|
2018-01-23 23:27:32 +08:00
|
|
|
case errcode.Error, *url.Error:
|
|
|
|
return nErr
|
|
|
|
default:
|
|
|
|
return defaultError
|
|
|
|
}
|
|
|
|
}
|
2018-03-30 08:25:12 +08:00
|
|
|
|
2018-04-07 08:11:17 +08:00
|
|
|
// WriteError writes `lastError` into `w` if not nil and return the next error `err`
|
|
|
|
func WriteError(w io.Writer, err error, lastError error) error {
|
|
|
|
if lastError != nil {
|
|
|
|
fmt.Fprintln(w, lastError)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
2018-06-13 05:21:08 +08:00
|
|
|
|
|
|
|
// Runtime is the default command to use to run the container.
|
|
|
|
func Runtime() string {
|
|
|
|
runtime := os.Getenv("BUILDAH_RUNTIME")
|
|
|
|
if runtime != "" {
|
|
|
|
return runtime
|
|
|
|
}
|
|
|
|
return DefaultRuntime
|
|
|
|
}
|
2018-06-07 23:25:47 +08:00
|
|
|
|
|
|
|
// StringInSlice returns a boolean indicating if the exact value s is present
|
|
|
|
// in the slice slice.
|
|
|
|
func StringInSlice(s string, slice []string) bool {
|
|
|
|
for _, v := range slice {
|
|
|
|
if v == s {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetHostIDs uses ID mappings to compute the host-level IDs that will
|
|
|
|
// correspond to a UID/GID pair in the container.
|
|
|
|
func GetHostIDs(uidmap, gidmap []specs.LinuxIDMapping, uid, gid uint32) (uint32, uint32, error) {
|
|
|
|
uidMapped := true
|
|
|
|
for _, m := range uidmap {
|
|
|
|
uidMapped = false
|
|
|
|
if uid >= m.ContainerID && uid < m.ContainerID+m.Size {
|
|
|
|
uid = (uid - m.ContainerID) + m.HostID
|
|
|
|
uidMapped = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !uidMapped {
|
|
|
|
return 0, 0, errors.Errorf("container uses ID mappings, but doesn't map UID %d", uid)
|
|
|
|
}
|
|
|
|
gidMapped := true
|
|
|
|
for _, m := range gidmap {
|
|
|
|
gidMapped = false
|
|
|
|
if gid >= m.ContainerID && gid < m.ContainerID+m.Size {
|
|
|
|
gid = (gid - m.ContainerID) + m.HostID
|
|
|
|
gidMapped = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !gidMapped {
|
|
|
|
return 0, 0, errors.Errorf("container uses ID mappings, but doesn't map GID %d", gid)
|
|
|
|
}
|
|
|
|
return uid, gid, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetHostRootIDs uses ID mappings in spec to compute the host-level IDs that will
|
|
|
|
// correspond to UID/GID 0/0 in the container.
|
|
|
|
func GetHostRootIDs(spec *specs.Spec) (uint32, uint32, error) {
|
|
|
|
if spec.Linux == nil {
|
|
|
|
return 0, 0, nil
|
|
|
|
}
|
|
|
|
return GetHostIDs(spec.Linux.UIDMappings, spec.Linux.GIDMappings, 0, 0)
|
|
|
|
}
|
2018-06-15 06:39:19 +08:00
|
|
|
|
|
|
|
// getHostIDMappings reads mappings from the named node under /proc.
|
|
|
|
func getHostIDMappings(path string) ([]specs.LinuxIDMapping, error) {
|
|
|
|
var mappings []specs.LinuxIDMapping
|
|
|
|
f, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error reading ID mappings from %q", path)
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
scanner := bufio.NewScanner(f)
|
|
|
|
for scanner.Scan() {
|
|
|
|
line := scanner.Text()
|
|
|
|
fields := strings.Fields(line)
|
|
|
|
if len(fields) != 3 {
|
|
|
|
return nil, errors.Errorf("line %q from %q has %d fields, not 3", line, path, len(fields))
|
|
|
|
}
|
|
|
|
cid, err := strconv.ParseUint(fields[0], 10, 32)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error parsing container ID value %q from line %q in %q", fields[0], line, path)
|
|
|
|
}
|
|
|
|
hid, err := strconv.ParseUint(fields[1], 10, 32)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error parsing host ID value %q from line %q in %q", fields[1], line, path)
|
|
|
|
}
|
|
|
|
size, err := strconv.ParseUint(fields[2], 10, 32)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error parsing size value %q from line %q in %q", fields[2], line, path)
|
|
|
|
}
|
|
|
|
mappings = append(mappings, specs.LinuxIDMapping{ContainerID: uint32(cid), HostID: uint32(hid), Size: uint32(size)})
|
|
|
|
}
|
|
|
|
return mappings, nil
|
|
|
|
}
|
|
|
|
|
2018-06-15 03:42:33 +08:00
|
|
|
// GetHostIDMappings reads mappings for the specified process (or the current
|
|
|
|
// process if pid is "self" or an empty string) from the kernel.
|
2018-06-15 06:39:19 +08:00
|
|
|
func GetHostIDMappings(pid string) ([]specs.LinuxIDMapping, []specs.LinuxIDMapping, error) {
|
|
|
|
if pid == "" {
|
|
|
|
pid = "self"
|
|
|
|
}
|
|
|
|
uidmap, err := getHostIDMappings(fmt.Sprintf("/proc/%s/uid_map", pid))
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
gidmap, err := getHostIDMappings(fmt.Sprintf("/proc/%s/gid_map", pid))
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return uidmap, gidmap, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetSubIDMappings reads mappings from /etc/subuid and /etc/subgid.
|
|
|
|
func GetSubIDMappings(user, group string) ([]specs.LinuxIDMapping, []specs.LinuxIDMapping, error) {
|
|
|
|
mappings, err := idtools.NewIDMappings(user, group)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, errors.Wrapf(err, "error reading subuid mappings for user %q and subgid mappings for group %q", user, group)
|
|
|
|
}
|
|
|
|
var uidmap, gidmap []specs.LinuxIDMapping
|
|
|
|
for _, m := range mappings.UIDs() {
|
|
|
|
uidmap = append(uidmap, specs.LinuxIDMapping{
|
|
|
|
ContainerID: uint32(m.ContainerID),
|
|
|
|
HostID: uint32(m.HostID),
|
|
|
|
Size: uint32(m.Size),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
for _, m := range mappings.GIDs() {
|
|
|
|
gidmap = append(gidmap, specs.LinuxIDMapping{
|
|
|
|
ContainerID: uint32(m.ContainerID),
|
|
|
|
HostID: uint32(m.HostID),
|
|
|
|
Size: uint32(m.Size),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return uidmap, gidmap, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ParseIDMappings parses mapping triples.
|
|
|
|
func ParseIDMappings(uidmap, gidmap []string) ([]idtools.IDMap, []idtools.IDMap, error) {
|
2018-12-11 16:35:52 +08:00
|
|
|
uid, err := idtools.ParseIDMap(uidmap, "userns-uid-map")
|
2018-06-15 06:39:19 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2018-12-11 16:35:52 +08:00
|
|
|
gid, err := idtools.ParseIDMap(gidmap, "userns-gid-map")
|
2018-06-15 06:39:19 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return uid, gid, nil
|
|
|
|
}
|
2018-06-15 03:42:33 +08:00
|
|
|
|
2018-06-29 01:59:42 +08:00
|
|
|
// GetPolicyContext sets up, initializes and returns a new context for the specified policy
|
|
|
|
func GetPolicyContext(ctx *types.SystemContext) (*signature.PolicyContext, error) {
|
|
|
|
policy, err := signature.DefaultPolicy(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
policyContext, err := signature.NewPolicyContext(policy)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return policyContext, nil
|
|
|
|
}
|
2019-01-09 05:57:49 +08:00
|
|
|
|
|
|
|
// logIfNotErrno logs the error message unless err is either nil or one of the
|
|
|
|
// listed syscall.Errno values. It returns true if it logged an error.
|
|
|
|
func logIfNotErrno(err error, what string, ignores ...syscall.Errno) (logged bool) {
|
|
|
|
if err == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if errno, isErrno := err.(syscall.Errno); isErrno {
|
|
|
|
for _, ignore := range ignores {
|
|
|
|
if errno == ignore {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
logrus.Error(what)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// LogIfNotRetryable logs "what" if err is set and is not an EINTR or EAGAIN
|
|
|
|
// syscall.Errno. Returns "true" if we can continue.
|
|
|
|
func LogIfNotRetryable(err error, what string) (retry bool) {
|
|
|
|
return !logIfNotErrno(err, what, syscall.EINTR, syscall.EAGAIN)
|
|
|
|
}
|
|
|
|
|
|
|
|
// LogIfUnexpectedWhileDraining logs "what" if err is set and is not an EINTR
|
|
|
|
// or EAGAIN or EIO syscall.Errno.
|
|
|
|
func LogIfUnexpectedWhileDraining(err error, what string) {
|
|
|
|
logIfNotErrno(err, what, syscall.EINTR, syscall.EAGAIN, syscall.EIO)
|
|
|
|
}
|