fix(executor): make pax tar builds reproducible again (#2384)

In v1.8.0 (commit 7410007) kaniko switched to using the pax tar header
format for compressing image layers, since this format allows for greater
precision in recording timestamps, however this inadvertendly broke the
"--reproducible" functionality, due to an bug in the underlying
go-containerregistry dependency which did not set the additional
timestamps in the pax header when canonicalizing image layers. This
oversight has since been fixed in the dependency.

This commit bumps the google/go-containerregistry dependency to the
first commit which has fixed the bug
(v0.13.1-0.20230201183932-824efc7772b0). It also bumps the version of
cloud.google.com/go/storage to v1.29.0 to be compatible with the higher
transitive dependency.
This commit is contained in:
Joël Pepper
2023-03-21 18:08:29 -04:00
committed by GitHub
parent 14ea7c4071
commit 0cbb7664de
873 changed files with 78917 additions and 29139 deletions
+13 -9
View File
@@ -104,14 +104,18 @@ func LoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) {
return &configFile, err
}
// TODO remove this temporary hack, which is used to warn about the deprecated ~/.dockercfg file
var printLegacyFileWarning bool
// Load reads the configuration files in the given directory, and sets up
// the auth config information and returns values.
// FIXME: use the internal golang config parser
func Load(configDir string) (*configfile.ConfigFile, error) {
printLegacyFileWarning = false
cfg, _, err := load(configDir)
return cfg, err
}
// TODO remove this temporary hack, which is used to warn about the deprecated ~/.dockercfg file
// so we can remove the bool return value and collapse this back into `Load`
func load(configDir string) (*configfile.ConfigFile, bool, error) {
printLegacyFileWarning := false
if configDir == "" {
configDir = Dir()
@@ -127,11 +131,11 @@ func Load(configDir string) (*configfile.ConfigFile, error) {
if err != nil {
err = errors.Wrap(err, filename)
}
return configFile, err
return configFile, printLegacyFileWarning, err
} else if !os.IsNotExist(err) {
// if file is there but we can't stat it for any reason other
// than it doesn't exist then stop
return configFile, errors.Wrap(err, filename)
return configFile, printLegacyFileWarning, errors.Wrap(err, filename)
}
// Can't find latest config file so check for the old one
@@ -140,16 +144,16 @@ func Load(configDir string) (*configfile.ConfigFile, error) {
printLegacyFileWarning = true
defer file.Close()
if err := configFile.LegacyLoadFromReader(file); err != nil {
return configFile, errors.Wrap(err, filename)
return configFile, printLegacyFileWarning, errors.Wrap(err, filename)
}
}
return configFile, nil
return configFile, printLegacyFileWarning, nil
}
// LoadDefaultConfigFile attempts to load the default config file and returns
// an initialized ConfigFile struct if none is found.
func LoadDefaultConfigFile(stderr io.Writer) *configfile.ConfigFile {
configFile, err := Load(Dir())
configFile, printLegacyFileWarning, err := load(Dir())
if err != nil {
fmt.Fprintf(stderr, "WARNING: Error loading config file: %v\n", err)
}
+1 -1
View File
@@ -119,7 +119,7 @@ func (configFile *ConfigFile) LegacyLoadFromReader(configData io.Reader) error {
// LoadFromReader reads the configuration data given and sets up the auth config
// information with given directory and populates the receiver object
func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error {
if err := json.NewDecoder(configData).Decode(&configFile); err != nil && !errors.Is(err, io.EOF) {
if err := json.NewDecoder(configData).Decode(configFile); err != nil && !errors.Is(err, io.EOF) {
return err
}
var err error
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package configfile
@@ -1,3 +1,4 @@
//go:build !windows && !darwin && !linux
// +build !windows,!darwin,!linux
package credentials
+1 -1
View File
@@ -7,7 +7,7 @@ import (
)
const (
remoteCredentialsPrefix = "docker-credential-"
remoteCredentialsPrefix = "docker-credential-" //nolint:gosec // ignore G101: Potential hardcoded credentials
tokenUsername = "<token>"
)
+3
View File
@@ -44,3 +44,6 @@ Thomas Berger <loki@lokis-chaos.de> Thomas Berger <tbe@users.noreply.github.com>
Samuel Karp <skarp@amazon.com> Samuel Karp <samuelkarp@users.noreply.github.com>
Justin Cormack <justin.cormack@docker.com>
sayboras <sayboras@yahoo.com>
CrazyMax <github@crazymax.dev>
CrazyMax <github@crazymax.dev> <1951866+crazy-max@users.noreply.github.com>
CrazyMax <github@crazymax.dev> <crazy-max@users.noreply.github.com>
+6 -2
View File
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1.3
ARG GO_VERSION=1.16
ARG GO_VERSION=1.16.15
ARG GORELEASER_XX_VERSION=1.2.5
FROM --platform=$BUILDPLATFORM crazymax/goreleaser-xx:${GORELEASER_XX_VERSION} AS goreleaser-xx
@@ -12,6 +12,10 @@ WORKDIR /go/src/github.com/docker/distribution
FROM base AS build
ENV GO111MODULE=auto
ENV CGO_ENABLED=0
# GIT_REF is used by goreleaser-xx to handle the proper git ref when available.
# It will fallback to the working tree info if empty and use "git tag --points-at"
# or "git describe" to define the version info.
ARG GIT_REF
ARG TARGETPLATFORM
ARG PKG="github.com/distribution/distribution"
ARG BUILDTAGS="include_oss include_gcs"
@@ -28,7 +32,7 @@ RUN --mount=type=bind,rw \
--files="LICENSE" \
--files="README.md"
FROM scratch AS artifacts
FROM scratch AS artifact
COPY --from=build /out/*.tar.gz /
COPY --from=build /out/*.zip /
COPY --from=build /out/*.sha256 /
+1 -1
View File
@@ -2,7 +2,7 @@
The Docker toolset to pack, ship, store, and deliver content.
This repository's main product is the Docker Registry 2.0 implementation
This repository provides the Docker Registry 2.0 implementation
for storing and distributing Docker images. It supersedes the
[docker/docker-registry](https://github.com/docker/docker-registry)
project with a new API design, focused around security and performance.
+16 -2
View File
@@ -1,3 +1,15 @@
// GITHUB_REF is the actual ref that triggers the workflow
// https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables
variable "GITHUB_REF" {
default = ""
}
target "_common" {
args = {
GIT_REF = GITHUB_REF
}
}
group "default" {
targets = ["image-local"]
}
@@ -8,12 +20,14 @@ target "docker-metadata-action" {
}
target "binary" {
inherits = ["_common"]
target = "binary"
output = ["./bin"]
}
target "artifact" {
target = "artifacts"
inherits = ["_common"]
target = "artifact"
output = ["./bin"]
}
@@ -30,7 +44,7 @@ target "artifact-all" {
}
target "image" {
inherits = ["docker-metadata-action"]
inherits = ["_common", "docker-metadata-action"]
}
target "image-local" {
-267
View File
@@ -1,267 +0,0 @@
package errcode
import (
"encoding/json"
"fmt"
"strings"
)
// ErrorCoder is the base interface for ErrorCode and Error allowing
// users of each to just call ErrorCode to get the real ID of each
type ErrorCoder interface {
ErrorCode() ErrorCode
}
// ErrorCode represents the error type. The errors are serialized via strings
// and the integer format may change and should *never* be exported.
type ErrorCode int
var _ error = ErrorCode(0)
// ErrorCode just returns itself
func (ec ErrorCode) ErrorCode() ErrorCode {
return ec
}
// Error returns the ID/Value
func (ec ErrorCode) Error() string {
// NOTE(stevvooe): Cannot use message here since it may have unpopulated args.
return strings.ToLower(strings.Replace(ec.String(), "_", " ", -1))
}
// Descriptor returns the descriptor for the error code.
func (ec ErrorCode) Descriptor() ErrorDescriptor {
d, ok := errorCodeToDescriptors[ec]
if !ok {
return ErrorCodeUnknown.Descriptor()
}
return d
}
// String returns the canonical identifier for this error code.
func (ec ErrorCode) String() string {
return ec.Descriptor().Value
}
// Message returned the human-readable error message for this error code.
func (ec ErrorCode) Message() string {
return ec.Descriptor().Message
}
// MarshalText encodes the receiver into UTF-8-encoded text and returns the
// result.
func (ec ErrorCode) MarshalText() (text []byte, err error) {
return []byte(ec.String()), nil
}
// UnmarshalText decodes the form generated by MarshalText.
func (ec *ErrorCode) UnmarshalText(text []byte) error {
desc, ok := idToDescriptors[string(text)]
if !ok {
desc = ErrorCodeUnknown.Descriptor()
}
*ec = desc.Code
return nil
}
// WithMessage creates a new Error struct based on the passed-in info and
// overrides the Message property.
func (ec ErrorCode) WithMessage(message string) Error {
return Error{
Code: ec,
Message: message,
}
}
// WithDetail creates a new Error struct based on the passed-in info and
// set the Detail property appropriately
func (ec ErrorCode) WithDetail(detail interface{}) Error {
return Error{
Code: ec,
Message: ec.Message(),
}.WithDetail(detail)
}
// WithArgs creates a new Error struct and sets the Args slice
func (ec ErrorCode) WithArgs(args ...interface{}) Error {
return Error{
Code: ec,
Message: ec.Message(),
}.WithArgs(args...)
}
// Error provides a wrapper around ErrorCode with extra Details provided.
type Error struct {
Code ErrorCode `json:"code"`
Message string `json:"message"`
Detail interface{} `json:"detail,omitempty"`
// TODO(duglin): See if we need an "args" property so we can do the
// variable substitution right before showing the message to the user
}
var _ error = Error{}
// ErrorCode returns the ID/Value of this Error
func (e Error) ErrorCode() ErrorCode {
return e.Code
}
// Error returns a human readable representation of the error.
func (e Error) Error() string {
return fmt.Sprintf("%s: %s", e.Code.Error(), e.Message)
}
// WithDetail will return a new Error, based on the current one, but with
// some Detail info added
func (e Error) WithDetail(detail interface{}) Error {
return Error{
Code: e.Code,
Message: e.Message,
Detail: detail,
}
}
// WithArgs uses the passed-in list of interface{} as the substitution
// variables in the Error's Message string, but returns a new Error
func (e Error) WithArgs(args ...interface{}) Error {
return Error{
Code: e.Code,
Message: fmt.Sprintf(e.Code.Message(), args...),
Detail: e.Detail,
}
}
// ErrorDescriptor provides relevant information about a given error code.
type ErrorDescriptor struct {
// Code is the error code that this descriptor describes.
Code ErrorCode
// Value provides a unique, string key, often captilized with
// underscores, to identify the error code. This value is used as the
// keyed value when serializing api errors.
Value string
// Message is a short, human readable decription of the error condition
// included in API responses.
Message string
// Description provides a complete account of the errors purpose, suitable
// for use in documentation.
Description string
// HTTPStatusCode provides the http status code that is associated with
// this error condition.
HTTPStatusCode int
}
// ParseErrorCode returns the value by the string error code.
// `ErrorCodeUnknown` will be returned if the error is not known.
func ParseErrorCode(value string) ErrorCode {
ed, ok := idToDescriptors[value]
if ok {
return ed.Code
}
return ErrorCodeUnknown
}
// Errors provides the envelope for multiple errors and a few sugar methods
// for use within the application.
type Errors []error
var _ error = Errors{}
func (errs Errors) Error() string {
switch len(errs) {
case 0:
return "<nil>"
case 1:
return errs[0].Error()
default:
msg := "errors:\n"
for _, err := range errs {
msg += err.Error() + "\n"
}
return msg
}
}
// Len returns the current number of errors.
func (errs Errors) Len() int {
return len(errs)
}
// MarshalJSON converts slice of error, ErrorCode or Error into a
// slice of Error - then serializes
func (errs Errors) MarshalJSON() ([]byte, error) {
var tmpErrs struct {
Errors []Error `json:"errors,omitempty"`
}
for _, daErr := range errs {
var err Error
switch daErr := daErr.(type) {
case ErrorCode:
err = daErr.WithDetail(nil)
case Error:
err = daErr
default:
err = ErrorCodeUnknown.WithDetail(daErr)
}
// If the Error struct was setup and they forgot to set the
// Message field (meaning its "") then grab it from the ErrCode
msg := err.Message
if msg == "" {
msg = err.Code.Message()
}
tmpErrs.Errors = append(tmpErrs.Errors, Error{
Code: err.Code,
Message: msg,
Detail: err.Detail,
})
}
return json.Marshal(tmpErrs)
}
// UnmarshalJSON deserializes []Error and then converts it into slice of
// Error or ErrorCode
func (errs *Errors) UnmarshalJSON(data []byte) error {
var tmpErrs struct {
Errors []Error
}
if err := json.Unmarshal(data, &tmpErrs); err != nil {
return err
}
var newErrs Errors
for _, daErr := range tmpErrs.Errors {
// If Message is empty or exactly matches the Code's message string
// then just use the Code, no need for a full Error struct
if daErr.Detail == nil && (daErr.Message == "" || daErr.Message == daErr.Code.Message()) {
// Error's w/o details get converted to ErrorCode
newErrs = append(newErrs, daErr.Code)
} else {
// Error's w/ details are untouched
newErrs = append(newErrs, Error{
Code: daErr.Code,
Message: daErr.Message,
Detail: daErr.Detail,
})
}
}
*errs = newErrs
return nil
}
-40
View File
@@ -1,40 +0,0 @@
package errcode
import (
"encoding/json"
"net/http"
)
// ServeJSON attempts to serve the errcode in a JSON envelope. It marshals err
// and sets the content-type header to 'application/json'. It will handle
// ErrorCoder and Errors, and if necessary will create an envelope.
func ServeJSON(w http.ResponseWriter, err error) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
var sc int
switch errs := err.(type) {
case Errors:
if len(errs) < 1 {
break
}
if err, ok := errs[0].(ErrorCoder); ok {
sc = err.ErrorCode().Descriptor().HTTPStatusCode
}
case ErrorCoder:
sc = errs.ErrorCode().Descriptor().HTTPStatusCode
err = Errors{err} // create an envelope.
default:
// We just have an unhandled error type, so just place in an envelope
// and move along.
err = Errors{err}
}
if sc == 0 {
sc = http.StatusInternalServerError
}
w.WriteHeader(sc)
return json.NewEncoder(w).Encode(err)
}
-138
View File
@@ -1,138 +0,0 @@
package errcode
import (
"fmt"
"net/http"
"sort"
"sync"
)
var (
errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{}
idToDescriptors = map[string]ErrorDescriptor{}
groupToDescriptors = map[string][]ErrorDescriptor{}
)
var (
// ErrorCodeUnknown is a generic error that can be used as a last
// resort if there is no situation-specific error message that can be used
ErrorCodeUnknown = Register("errcode", ErrorDescriptor{
Value: "UNKNOWN",
Message: "unknown error",
Description: `Generic error returned when the error does not have an
API classification.`,
HTTPStatusCode: http.StatusInternalServerError,
})
// ErrorCodeUnsupported is returned when an operation is not supported.
ErrorCodeUnsupported = Register("errcode", ErrorDescriptor{
Value: "UNSUPPORTED",
Message: "The operation is unsupported.",
Description: `The operation was unsupported due to a missing
implementation or invalid set of parameters.`,
HTTPStatusCode: http.StatusMethodNotAllowed,
})
// ErrorCodeUnauthorized is returned if a request requires
// authentication.
ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{
Value: "UNAUTHORIZED",
Message: "authentication required",
Description: `The access controller was unable to authenticate
the client. Often this will be accompanied by a
Www-Authenticate HTTP response header indicating how to
authenticate.`,
HTTPStatusCode: http.StatusUnauthorized,
})
// ErrorCodeDenied is returned if a client does not have sufficient
// permission to perform an action.
ErrorCodeDenied = Register("errcode", ErrorDescriptor{
Value: "DENIED",
Message: "requested access to the resource is denied",
Description: `The access controller denied access for the
operation on a resource.`,
HTTPStatusCode: http.StatusForbidden,
})
// ErrorCodeUnavailable provides a common error to report unavailability
// of a service or endpoint.
ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{
Value: "UNAVAILABLE",
Message: "service unavailable",
Description: "Returned when a service is not available",
HTTPStatusCode: http.StatusServiceUnavailable,
})
// ErrorCodeTooManyRequests is returned if a client attempts too many
// times to contact a service endpoint.
ErrorCodeTooManyRequests = Register("errcode", ErrorDescriptor{
Value: "TOOMANYREQUESTS",
Message: "too many requests",
Description: `Returned when a client attempts to contact a
service too many times`,
HTTPStatusCode: http.StatusTooManyRequests,
})
)
var nextCode = 1000
var registerLock sync.Mutex
// Register will make the passed-in error known to the environment and
// return a new ErrorCode
func Register(group string, descriptor ErrorDescriptor) ErrorCode {
registerLock.Lock()
defer registerLock.Unlock()
descriptor.Code = ErrorCode(nextCode)
if _, ok := idToDescriptors[descriptor.Value]; ok {
panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value))
}
if _, ok := errorCodeToDescriptors[descriptor.Code]; ok {
panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code))
}
groupToDescriptors[group] = append(groupToDescriptors[group], descriptor)
errorCodeToDescriptors[descriptor.Code] = descriptor
idToDescriptors[descriptor.Value] = descriptor
nextCode++
return descriptor.Code
}
type byValue []ErrorDescriptor
func (a byValue) Len() int { return len(a) }
func (a byValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value }
// GetGroupNames returns the list of Error group names that are registered
func GetGroupNames() []string {
keys := []string{}
for k := range groupToDescriptors {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}
// GetErrorCodeGroup returns the named group of error descriptors
func GetErrorCodeGroup(name string) []ErrorDescriptor {
desc := groupToDescriptors[name]
sort.Sort(byValue(desc))
return desc
}
// GetErrorAllDescriptors returns a slice of all ErrorDescriptors that are
// registered, irrespective of what group they're in
func GetErrorAllDescriptors() []ErrorDescriptor {
result := []ErrorDescriptor{}
for _, group := range GetGroupNames() {
result = append(result, GetErrorCodeGroup(group)...)
}
sort.Sort(byValue(result))
return result
}
@@ -169,8 +169,8 @@ func Erase(helper Helper, reader io.Reader) error {
return helper.Delete(serverURL)
}
//List returns all the serverURLs of keys in
//the OS store as a list of strings
// List returns all the serverURLs of keys in
// the OS store as a list of strings
func List(helper Helper, writer io.Writer) error {
accts, err := helper.List()
if err != nil {
@@ -179,8 +179,8 @@ func List(helper Helper, writer io.Writer) error {
return json.NewEncoder(writer).Encode(accts)
}
//PrintVersion outputs the current version.
// PrintVersion outputs the current version.
func PrintVersion(writer io.Writer) error {
fmt.Fprintln(writer, Version)
fmt.Fprintf(writer, "%s (%s) %s\n", Name, Package, Version)
return nil
}
+14 -2
View File
@@ -1,4 +1,16 @@
package credentials
// Version holds a string describing the current version
const Version = "0.6.4"
var (
// Name is filled at linking time
Name = ""
// Package is filled at linking time
Package = "github.com/docker/docker-credential-helpers"
// Version holds the complete version number. Filled in at linking time.
Version = "v0.0.0+unknown"
// Revision is filled with the VCS (e.g. git) revision being used to build
// the program at linking time.
Revision = ""
)
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package api // import "github.com/docker/docker/api"
+54 -2
View File
@@ -24,7 +24,7 @@ info:
title: "Docker Engine API"
version: "1.41"
x-logo:
url: "https://docs.docker.com/images/logo-docker-main.png"
url: "https://docs.docker.com/assets/images/logo-docker-main.png"
description: |
The Engine API is an HTTP API served by Docker Engine. It is the API the
Docker client uses to communicate with the Engine, so everything the Docker
@@ -1891,23 +1891,52 @@ definitions:
BuildCache:
type: "object"
description: |
BuildCache contains information about a build cache record.
properties:
ID:
type: "string"
description: |
Unique ID of the build cache record.
example: "ndlpt0hhvkqcdfkputsk4cq9c"
Parent:
description: |
ID of the parent build cache record.
type: "string"
example: "hw53o5aio51xtltp5xjp8v7fx"
Type:
type: "string"
description: |
Cache record type.
example: "regular"
# see https://github.com/moby/buildkit/blob/fce4a32258dc9d9664f71a4831d5de10f0670677/client/diskusage.go#L75-L84
enum:
- "internal"
- "frontend"
- "source.local"
- "source.git.checkout"
- "exec.cachemount"
- "regular"
Description:
type: "string"
description: |
Description of the build-step that produced the build cache.
example: "mount / from exec /bin/sh -c echo 'Binary::apt::APT::Keep-Downloaded-Packages \"true\";' > /etc/apt/apt.conf.d/keep-cache"
InUse:
type: "boolean"
description: |
Indicates if the build cache is in use.
example: false
Shared:
type: "boolean"
description: |
Indicates if the build cache is shared.
example: true
Size:
description: |
Amount of disk space used by the build cache (in bytes).
type: "integer"
example: 51
CreatedAt:
description: |
Date and time at which the build cache was created in
@@ -1925,6 +1954,7 @@ definitions:
example: "2017-08-09T07:09:37.632105588Z"
UsageCount:
type: "integer"
example: 26
ImageID:
type: "object"
@@ -3347,7 +3377,7 @@ definitions:
Limits:
description: "Define resources limits."
$ref: "#/definitions/Limit"
Reservation:
Reservations:
description: "Define resources reservation."
$ref: "#/definitions/ResourceObject"
RestartPolicy:
@@ -5415,6 +5445,28 @@ paths:
`/?[a-zA-Z0-9][a-zA-Z0-9_.-]+`.
type: "string"
pattern: "^/?[a-zA-Z0-9][a-zA-Z0-9_.-]+$"
- name: "platform"
in: "query"
description: |
Platform in the format `os[/arch[/variant]]` used for image lookup.
When specified, the daemon checks if the requested image is present
in the local image cache with the given OS and Architecture, and
otherwise returns a `404` status.
If the option is not set, the host's native OS and Architecture are
used to look up the image in the image cache. However, if no platform
is passed and the given image does exist in the local image cache,
but its OS or architecture does not match, the container is created
with the available image, and a warning is added to the `Warnings`
field in the response, for example;
WARNING: The requested image's platform (linux/arm64/v8) does not
match the detected host platform (linux/amd64) and no
specific platform was requested
type: "string"
default: ""
- name: "body"
in: "body"
description: "Container to create"
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package container // import "github.com/docker/docker/api/types/container"
+5 -4
View File
@@ -257,10 +257,10 @@ func (b *Builder) dispatchDockerfileWithCancellation(parseResult []instructions.
totalCommands += len(stage.Commands)
}
shlex := shell.NewLex(escapeToken)
for _, meta := range metaArgs {
currentCommandIndex = printCommand(b.Stdout, currentCommandIndex, totalCommands, &meta)
for i := range metaArgs {
currentCommandIndex = printCommand(b.Stdout, currentCommandIndex, totalCommands, &metaArgs[i])
err := processMetaArg(meta, shlex, buildArgs)
err := processMetaArg(metaArgs[i], shlex, buildArgs)
if err != nil {
return nil, err
}
@@ -268,7 +268,8 @@ func (b *Builder) dispatchDockerfileWithCancellation(parseResult []instructions.
stagesResults := newStagesBuildResults()
for _, stage := range parseResult {
for _, s := range parseResult {
stage := s
if err := stagesResults.checkStageNameAvailable(stage.Name); err != nil {
return nil, err
}
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
+1 -1
View File
@@ -11,7 +11,7 @@ import (
// MakeGitContext returns a Context from gitURL that is cloned in a temporary directory.
func MakeGitContext(gitURL string) (builder.Source, error) {
root, err := git.Clone(gitURL)
root, err := git.Clone(gitURL, git.WithIsolatedConfig(true))
if err != nil {
return nil, err
}
+44 -20
View File
@@ -17,21 +17,37 @@ type gitRepo struct {
remote string
ref string
subdir string
isolateConfig bool
}
type CloneOption func(*gitRepo)
// WithIsolatedConfig disables reading the user or system gitconfig files when
// performing Git operations.
func WithIsolatedConfig(v bool) CloneOption {
return func(gr *gitRepo) {
gr.isolateConfig = v
}
}
// Clone clones a repository into a newly created directory which
// will be under "docker-build-git"
func Clone(remoteURL string) (string, error) {
func Clone(remoteURL string, opts ...CloneOption) (string, error) {
repo, err := parseRemoteURL(remoteURL)
if err != nil {
return "", err
}
return cloneGitRepo(repo)
for _, opt := range opts {
opt(&repo)
}
return repo.clone()
}
func cloneGitRepo(repo gitRepo) (checkoutDir string, err error) {
func (repo gitRepo) clone() (checkoutDir string, err error) {
fetch := fetchArgs(repo.remote, repo.ref)
root, err := ioutil.TempDir("", "docker-build-git")
@@ -45,21 +61,21 @@ func cloneGitRepo(repo gitRepo) (checkoutDir string, err error) {
}
}()
if out, err := gitWithinDir(root, "init"); err != nil {
if out, err := repo.gitWithinDir(root, "init"); err != nil {
return "", errors.Wrapf(err, "failed to init repo at %s: %s", root, out)
}
// Add origin remote for compatibility with previous implementation that
// used "git clone" and also to make sure local refs are created for branches
if out, err := gitWithinDir(root, "remote", "add", "origin", repo.remote); err != nil {
if out, err := repo.gitWithinDir(root, "remote", "add", "origin", repo.remote); err != nil {
return "", errors.Wrapf(err, "failed add origin repo at %s: %s", repo.remote, out)
}
if output, err := gitWithinDir(root, fetch...); err != nil {
if output, err := repo.gitWithinDir(root, fetch...); err != nil {
return "", errors.Wrapf(err, "error fetching: %s", output)
}
checkoutDir, err = checkoutGit(root, repo.ref, repo.subdir)
checkoutDir, err = repo.checkout(root)
if err != nil {
return "", err
}
@@ -163,20 +179,20 @@ func supportsShallowClone(remoteURL string) bool {
return true
}
func checkoutGit(root, ref, subdir string) (string, error) {
func (repo gitRepo) checkout(root string) (string, error) {
// Try checking out by ref name first. This will work on branches and sets
// .git/HEAD to the current branch name
if output, err := gitWithinDir(root, "checkout", ref); err != nil {
if output, err := repo.gitWithinDir(root, "checkout", repo.ref); err != nil {
// If checking out by branch name fails check out the last fetched ref
if _, err2 := gitWithinDir(root, "checkout", "FETCH_HEAD"); err2 != nil {
return "", errors.Wrapf(err, "error checking out %s: %s", ref, output)
if _, err2 := repo.gitWithinDir(root, "checkout", "FETCH_HEAD"); err2 != nil {
return "", errors.Wrapf(err, "error checking out %s: %s", repo.ref, output)
}
}
if subdir != "" {
newCtx, err := symlink.FollowSymlinkInScope(filepath.Join(root, subdir), root)
if repo.subdir != "" {
newCtx, err := symlink.FollowSymlinkInScope(filepath.Join(root, repo.subdir), root)
if err != nil {
return "", errors.Wrapf(err, "error setting git context, %q not within git root", subdir)
return "", errors.Wrapf(err, "error setting git context, %q not within git root", repo.subdir)
}
fi, err := os.Stat(newCtx)
@@ -192,13 +208,21 @@ func checkoutGit(root, ref, subdir string) (string, error) {
return root, nil
}
func gitWithinDir(dir string, args ...string) ([]byte, error) {
a := []string{"--work-tree", dir, "--git-dir", filepath.Join(dir, ".git")}
return git(append(a, args...)...)
}
func (repo gitRepo) gitWithinDir(dir string, args ...string) ([]byte, error) {
args = append([]string{"-c", "protocol.file.allow=never"}, args...) // Block sneaky repositories from using repos from the filesystem as submodules.
cmd := exec.Command("git", args...)
cmd.Dir = dir
// Disable unsafe remote protocols.
cmd.Env = append(cmd.Env, "GIT_PROTOCOL_FROM_USER=0")
func git(args ...string) ([]byte, error) {
return exec.Command("git", args...).CombinedOutput()
if repo.isolateConfig {
cmd.Env = append(cmd.Env,
"GIT_CONFIG_NOSYSTEM=1", // Disable reading from system gitconfig.
"HOME=/dev/null", // Disable reading from user gitconfig.
)
}
return cmd.CombinedOutput()
}
// isGitTransport returns true if the provided str is a git transport by inspecting
-3
View File
@@ -135,9 +135,6 @@ func NewClientWithOpts(ops ...Opt) (*Client, error) {
}
}
if _, ok := c.client.Transport.(http.RoundTripper); !ok {
return nil, fmt.Errorf("unable to verify TLS configuration, invalid transport %v", c.client.Transport)
}
if c.scheme == "" {
c.scheme = "http"
+1
View File
@@ -1,3 +1,4 @@
//go:build linux || freebsd || openbsd || netbsd || darwin || solaris || illumos || dragonfly
// +build linux freebsd openbsd netbsd darwin solaris illumos dragonfly
package client // import "github.com/docker/docker/client"
+15 -4
View File
@@ -4,8 +4,8 @@ import (
"context"
"encoding/json"
"net/url"
"path"
"github.com/containerd/containerd/platforms"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/versions"
@@ -16,7 +16,6 @@ type configWrapper struct {
*container.Config
HostConfig *container.HostConfig
NetworkingConfig *network.NetworkingConfig
Platform *specs.Platform
}
// ContainerCreate creates a new container based in the given configuration.
@@ -38,8 +37,8 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
}
query := url.Values{}
if platform != nil {
query.Set("platform", platforms.Format(*platform))
if p := formatPlatform(platform); p != "" {
query.Set("platform", p)
}
if containerName != "" {
@@ -61,3 +60,15 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
err = json.NewDecoder(serverResp.body).Decode(&response)
return response, err
}
// formatPlatform returns a formatted string representing platform (e.g. linux/arm/v7).
//
// Similar to containerd's platforms.Format(), but does allow components to be
// omitted (e.g. pass "architecture" only, without "os":
// https://github.com/containerd/containerd/blob/v1.5.2/platforms/platforms.go#L243-L263
func formatPlatform(platform *specs.Platform) string {
if platform == nil {
return ""
}
return path.Join(platform.OS, platform.Architecture, platform.Variant)
}
+4 -8
View File
@@ -150,10 +150,8 @@ func (cli *Client) doRequest(ctx context.Context, req *http.Request) (serverResp
if err.Timeout() {
return serverResp, ErrorConnectionFailed(cli.host)
}
if !err.Temporary() {
if strings.Contains(err.Error(), "connection refused") || strings.Contains(err.Error(), "dial unix") {
return serverResp, ErrorConnectionFailed(cli.host)
}
if strings.Contains(err.Error(), "connection refused") || strings.Contains(err.Error(), "dial unix") {
return serverResp, ErrorConnectionFailed(cli.host)
}
}
@@ -242,10 +240,8 @@ func (cli *Client) addHeaders(req *http.Request, headers headers) *http.Request
req.Header.Set(k, v)
}
if headers != nil {
for k, v := range headers {
req.Header[k] = v
}
for k, v := range headers {
req.Header[k] = v
}
return req
}
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package container // import "github.com/docker/docker/container"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package container // import "github.com/docker/docker/container"
@@ -1,3 +1,4 @@
//go:build !linux && !windows && !freebsd
// +build !linux,!windows,!freebsd
package graphdriver // import "github.com/docker/docker/daemon/graphdriver"
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package loggerutils
+1
View File
@@ -1,3 +1,4 @@
//go:build linux || freebsd
// +build linux freebsd
package logger // import "github.com/docker/docker/daemon/logger"
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux && !freebsd
// +build !linux,!freebsd
package logger // import "github.com/docker/docker/daemon/logger"
+1 -1
View File
@@ -20,7 +20,7 @@ var basicFunctions = template.FuncMap{
},
"split": strings.Split,
"join": strings.Join,
"title": strings.Title,
"title": strings.Title, //nolint:staticcheck // SA1019: strings.Title is deprecated: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead.
"lower": strings.ToLower,
"upper": strings.ToUpper,
"pad": padWithSpace,
+1
View File
@@ -1,3 +1,4 @@
//go:build !autogen
// +build !autogen
// Package dockerversion is auto-generated at build-time
+3 -141
View File
@@ -1,78 +1,11 @@
package errdefs // import "github.com/docker/docker/errdefs"
import (
"fmt"
"net/http"
containerderrors "github.com/containerd/containerd/errdefs"
"github.com/docker/distribution/registry/api/errcode"
"github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// GetHTTPErrorStatusCode retrieves status code from error message.
func GetHTTPErrorStatusCode(err error) int {
if err == nil {
logrus.WithFields(logrus.Fields{"error": err}).Error("unexpected HTTP error handling")
return http.StatusInternalServerError
}
var statusCode int
// Stop right there
// Are you sure you should be adding a new error class here? Do one of the existing ones work?
// Note that the below functions are already checking the error causal chain for matches.
switch {
case IsNotFound(err):
statusCode = http.StatusNotFound
case IsInvalidParameter(err):
statusCode = http.StatusBadRequest
case IsConflict(err):
statusCode = http.StatusConflict
case IsUnauthorized(err):
statusCode = http.StatusUnauthorized
case IsUnavailable(err):
statusCode = http.StatusServiceUnavailable
case IsForbidden(err):
statusCode = http.StatusForbidden
case IsNotModified(err):
statusCode = http.StatusNotModified
case IsNotImplemented(err):
statusCode = http.StatusNotImplemented
case IsSystem(err) || IsUnknown(err) || IsDataLoss(err) || IsDeadline(err) || IsCancelled(err):
statusCode = http.StatusInternalServerError
default:
statusCode = statusCodeFromGRPCError(err)
if statusCode != http.StatusInternalServerError {
return statusCode
}
statusCode = statusCodeFromContainerdError(err)
if statusCode != http.StatusInternalServerError {
return statusCode
}
statusCode = statusCodeFromDistributionError(err)
if statusCode != http.StatusInternalServerError {
return statusCode
}
if e, ok := err.(causer); ok {
return GetHTTPErrorStatusCode(e.Cause())
}
logrus.WithFields(logrus.Fields{
"module": "api",
"error_type": fmt.Sprintf("%T", err),
}).Debugf("FIXME: Got an API for which error does not match any expected type!!!: %+v", err)
}
if statusCode == 0 {
statusCode = http.StatusInternalServerError
}
return statusCode
}
// FromStatusCode creates an errdef error, based on the provided HTTP status-code
func FromStatusCode(err error, statusCode int) error {
if err == nil {
@@ -100,10 +33,10 @@ func FromStatusCode(err error, statusCode int) error {
err = System(err)
}
default:
logrus.WithFields(logrus.Fields{
logrus.WithError(err).WithFields(logrus.Fields{
"module": "api",
"status_code": fmt.Sprintf("%d", statusCode),
}).Debugf("FIXME: Got an status-code for which error does not match any expected type!!!: %d", statusCode)
"status_code": statusCode,
}).Debug("FIXME: Got an status-code for which error does not match any expected type!!!")
switch {
case statusCode >= 200 && statusCode < 400:
@@ -118,74 +51,3 @@ func FromStatusCode(err error, statusCode int) error {
}
return err
}
// statusCodeFromGRPCError returns status code according to gRPC error
func statusCodeFromGRPCError(err error) int {
switch status.Code(err) {
case codes.InvalidArgument: // code 3
return http.StatusBadRequest
case codes.NotFound: // code 5
return http.StatusNotFound
case codes.AlreadyExists: // code 6
return http.StatusConflict
case codes.PermissionDenied: // code 7
return http.StatusForbidden
case codes.FailedPrecondition: // code 9
return http.StatusBadRequest
case codes.Unauthenticated: // code 16
return http.StatusUnauthorized
case codes.OutOfRange: // code 11
return http.StatusBadRequest
case codes.Unimplemented: // code 12
return http.StatusNotImplemented
case codes.Unavailable: // code 14
return http.StatusServiceUnavailable
default:
// codes.Canceled(1)
// codes.Unknown(2)
// codes.DeadlineExceeded(4)
// codes.ResourceExhausted(8)
// codes.Aborted(10)
// codes.Internal(13)
// codes.DataLoss(15)
return http.StatusInternalServerError
}
}
// statusCodeFromDistributionError returns status code according to registry errcode
// code is loosely based on errcode.ServeJSON() in docker/distribution
func statusCodeFromDistributionError(err error) int {
switch errs := err.(type) {
case errcode.Errors:
if len(errs) < 1 {
return http.StatusInternalServerError
}
if _, ok := errs[0].(errcode.ErrorCoder); ok {
return statusCodeFromDistributionError(errs[0])
}
case errcode.ErrorCoder:
return errs.ErrorCode().Descriptor().HTTPStatusCode
}
return http.StatusInternalServerError
}
// statusCodeFromContainerdError returns status code for containerd errors when
// consumed directly (not through gRPC)
func statusCodeFromContainerdError(err error) int {
switch {
case containerderrors.IsInvalidArgument(err):
return http.StatusBadRequest
case containerderrors.IsNotFound(err):
return http.StatusNotFound
case containerderrors.IsAlreadyExists(err):
return http.StatusConflict
case containerderrors.IsFailedPrecondition(err):
return http.StatusPreconditionFailed
case containerderrors.IsUnavailable(err):
return http.StatusServiceUnavailable
case containerderrors.IsNotImplemented(err):
return http.StatusNotImplemented
default:
return http.StatusInternalServerError
}
}
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package layer // import "github.com/docker/docker/layer"
+1
View File
@@ -1,3 +1,4 @@
//go:build linux || freebsd || darwin || openbsd
// +build linux freebsd darwin openbsd
package layer // import "github.com/docker/docker/layer"
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux
package oci // import "github.com/docker/docker/oci"
+1 -1
View File
@@ -13,7 +13,7 @@ import (
// that *only* passes `a` as value: `echo a > /sys/fs/cgroup/1/devices.allow, which would be
// the "implicit" equivalent of "a *:* rwm". Source-code also looks to confirm this, and returns
// early for "a" (all); https://github.com/torvalds/linux/blob/v5.10/security/device_cgroup.c#L614-L642
// nolint: gosimple
//nolint: gosimple
var deviceCgroupRuleRegex = regexp.MustCompile("^([acb]) ([0-9]+|\\*):([0-9]+|\\*) ([rwm]{1,3})$")
// SetCapabilities sets the provided capabilities on the spec
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux
package archive // import "github.com/docker/docker/pkg/archive"
+3 -2
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package archive // import "github.com/docker/docker/pkg/archive"
@@ -51,8 +52,8 @@ func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (
// Currently go does not fill in the major/minors
if s.Mode&unix.S_IFBLK != 0 ||
s.Mode&unix.S_IFCHR != 0 {
hdr.Devmajor = int64(unix.Major(uint64(s.Rdev))) // nolint: unconvert
hdr.Devminor = int64(unix.Minor(uint64(s.Rdev))) // nolint: unconvert
hdr.Devmajor = int64(unix.Major(uint64(s.Rdev))) //nolint: unconvert
hdr.Devminor = int64(unix.Minor(uint64(s.Rdev))) //nolint: unconvert
}
}
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux
package archive // import "github.com/docker/docker/pkg/archive"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package archive // import "github.com/docker/docker/pkg/archive"
+10
View File
@@ -354,6 +354,16 @@ func RebaseArchiveEntries(srcContent io.Reader, oldBase, newBase string) io.Read
return
}
// Ignoring GoSec G110. See https://github.com/securego/gosec/pull/433
// and https://cure53.de/pentest-report_opa.pdf, which recommends to
// replace io.Copy with io.CopyN7. The latter allows to specify the
// maximum number of bytes that should be read. By properly defining
// the limit, it can be assured that a GZip compression bomb cannot
// easily cause a Denial-of-Service.
// After reviewing with @tonistiigi and @cpuguy83, this should not
// affect us, because here we do not read into memory, hence should
// not be vulnerable to this code consuming memory.
//nolint:gosec // G110: Potential DoS vulnerability via decompression bomb (gosec)
if _, err = io.Copy(rebasedTar, srcTar); err != nil {
w.CloseWithError(err)
return
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package archive // import "github.com/docker/docker/pkg/archive"
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux
package archive // import "github.com/docker/docker/pkg/archive"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows && !linux
// +build !windows,!linux
package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive"
+2 -1
View File
@@ -1,4 +1,5 @@
//+build !windows
//go:build !windows
// +build !windows
package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package containerfs // import "github.com/docker/docker/pkg/containerfs"
+1
View File
@@ -1,3 +1,4 @@
//go:build linux || freebsd
// +build linux freebsd
package fileutils // import "github.com/docker/docker/pkg/fileutils"
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux
package homedir // import "github.com/docker/docker/pkg/homedir"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package homedir // import "github.com/docker/docker/pkg/homedir"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package idtools // import "github.com/docker/docker/pkg/idtools"
@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux
package idtools // import "github.com/docker/docker/pkg/idtools"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package idtools // import "github.com/docker/docker/pkg/idtools"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package ioutils // import "github.com/docker/docker/pkg/ioutils"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
// Package kernel provides helper function to get, parse and compare kernel
+1
View File
@@ -1,3 +1,4 @@
//go:build darwin
// +build darwin
// Package kernel provides helper function to get, parse and compare kernel
+1
View File
@@ -1,3 +1,4 @@
//go:build linux || freebsd || openbsd
// +build linux freebsd openbsd
// Package kernel provides helper function to get, parse and compare kernel
@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux
package kernel // import "github.com/docker/docker/pkg/parsers/kernel"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package plugins // import "github.com/docker/docker/pkg/plugins"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package plugins // import "github.com/docker/docker/pkg/plugins"
+1
View File
@@ -1,3 +1,4 @@
//go:build freebsd || darwin
// +build freebsd darwin
package reexec // import "github.com/docker/docker/pkg/reexec"
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux && !windows && !freebsd && !darwin
// +build !linux,!windows,!freebsd,!darwin
package reexec // import "github.com/docker/docker/pkg/reexec"
+1
View File
@@ -1,3 +1,4 @@
//go:build !mips && !mipsle && !mips64 && !mips64le
// +build !mips,!mipsle,!mips64,!mips64le
package signal // import "github.com/docker/docker/pkg/signal"
+1
View File
@@ -1,3 +1,4 @@
//go:build linux && (mips || mipsle || mips64 || mips64le)
// +build linux
// +build mips mipsle mips64 mips64le
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package signal // import "github.com/docker/docker/pkg/signal"
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux && !darwin && !freebsd && !windows
// +build !linux,!darwin,!freebsd,!windows
package signal // import "github.com/docker/docker/pkg/signal"
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux && !windows
// +build !linux,!windows
package sysinfo // import "github.com/docker/docker/pkg/sysinfo"
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux && !windows
// +build !linux,!windows
package sysinfo // import "github.com/docker/docker/pkg/sysinfo"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package system // import "github.com/docker/docker/pkg/system"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package system // import "github.com/docker/docker/pkg/system"
+1
View File
@@ -1,3 +1,4 @@
//go:build windows && !no_lcow
// +build windows,!no_lcow
package system // import "github.com/docker/docker/pkg/system"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows || (windows && no_lcow)
// +build !windows windows,no_lcow
package system // import "github.com/docker/docker/pkg/system"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package system // import "github.com/docker/docker/pkg/system"
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux && !windows
// +build !linux,!windows
package system // import "github.com/docker/docker/pkg/system"
+1 -6
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package system // import "github.com/docker/docker/pkg/system"
@@ -6,12 +7,6 @@ import (
"golang.org/x/sys/unix"
)
// Mknod creates a filesystem node (file, device special file or named pipe) named path
// with attributes specified by mode and dev.
func Mknod(path string, mode uint32, dev int) error {
return unix.Mknod(path, mode, dev)
}
// Mkdev is used to build the value of linux devices (in /dev/) which specifies major
// and minor number of the newly created device special file.
// Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes.
+14
View File
@@ -0,0 +1,14 @@
//go:build freebsd
// +build freebsd
package system // import "github.com/docker/docker/pkg/system"
import (
"golang.org/x/sys/unix"
)
// Mknod creates a filesystem node (file, device special file or named pipe) named path
// with attributes specified by mode and dev.
func Mknod(path string, mode uint32, dev int) error {
return unix.Mknod(path, mode, uint64(dev))
}
+14
View File
@@ -0,0 +1,14 @@
//go:build !freebsd && !windows
// +build !freebsd,!windows
package system // import "github.com/docker/docker/pkg/system"
import (
"golang.org/x/sys/unix"
)
// Mknod creates a filesystem node (file, device special file or named pipe) named path
// with attributes specified by mode and dev.
func Mknod(path string, mode uint32, dev int) error {
return unix.Mknod(path, mode, dev)
}
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package system // import "github.com/docker/docker/pkg/system"
+1
View File
@@ -1,3 +1,4 @@
//go:build linux || freebsd || darwin
// +build linux freebsd darwin
package system // import "github.com/docker/docker/pkg/system"
+1
View File
@@ -1,3 +1,4 @@
//go:build !darwin && !windows
// +build !darwin,!windows
package system // import "github.com/docker/docker/pkg/system"
+1
View File
@@ -1,3 +1,4 @@
//go:build freebsd || netbsd
// +build freebsd netbsd
package system // import "github.com/docker/docker/pkg/system"
+1 -1
View File
@@ -9,7 +9,7 @@ func fromStatT(s *syscall.Stat_t) (*StatT, error) {
uid: s.Uid,
gid: s.Gid,
// the type is 32bit on mips
rdev: uint64(s.Rdev), // nolint: unconvert
rdev: uint64(s.Rdev), //nolint: unconvert
mtim: s.Mtim}, nil
}
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package system // import "github.com/docker/docker/pkg/system"
+1
View File
@@ -1,3 +1,4 @@
//go:build linux || freebsd
// +build linux freebsd
package system // import "github.com/docker/docker/pkg/system"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package system // import "github.com/docker/docker/pkg/system"
+1
View File
@@ -1,3 +1,4 @@
//go:build linux || freebsd
// +build linux freebsd
package system // import "github.com/docker/docker/pkg/system"
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux && !freebsd
// +build !linux,!freebsd
package system // import "github.com/docker/docker/pkg/system"
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux
package system // import "github.com/docker/docker/pkg/system"
+3 -1
View File
@@ -126,7 +126,9 @@ func (p *Plugin) Set(args []string) error {
// TODO(vieux): lots of code duplication here, needs to be refactored.
next:
for _, s := range sets {
for _, set := range sets {
s := set
// range over all the envs in the config
for _, env := range p.PluginObj.Config.Env {
// found the env in the config
+1
View File
@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux
package v2 // import "github.com/docker/docker/plugin/v2"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package runconfig // import "github.com/docker/docker/runconfig"
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package runconfig // import "github.com/docker/docker/runconfig"
+1
View File
@@ -1,3 +1,4 @@
//go:build linux || freebsd || darwin
// +build linux freebsd darwin
package mounts // import "github.com/docker/docker/volume/mounts"
+58 -12
View File
@@ -2,7 +2,6 @@ package units
import (
"fmt"
"regexp"
"strconv"
"strings"
)
@@ -26,16 +25,17 @@ const (
PiB = 1024 * TiB
)
type unitMap map[string]int64
type unitMap map[byte]int64
var (
decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB}
binaryMap = unitMap{"k": KiB, "m": MiB, "g": GiB, "t": TiB, "p": PiB}
sizeRegex = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[iI]?[bB]?$`)
decimalMap = unitMap{'k': KB, 'm': MB, 'g': GB, 't': TB, 'p': PB}
binaryMap = unitMap{'k': KiB, 'm': MiB, 'g': GiB, 't': TiB, 'p': PiB}
)
var decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
var binaryAbbrs = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
var (
decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
binaryAbbrs = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
)
func getSizeAndUnit(size float64, base float64, _map []string) (float64, string) {
i := 0
@@ -89,20 +89,66 @@ func RAMInBytes(size string) (int64, error) {
// Parses the human-readable size string into the amount it represents.
func parseSize(sizeStr string, uMap unitMap) (int64, error) {
matches := sizeRegex.FindStringSubmatch(sizeStr)
if len(matches) != 4 {
// TODO: rewrite to use strings.Cut if there's a space
// once Go < 1.18 is deprecated.
sep := strings.LastIndexAny(sizeStr, "01234567890. ")
if sep == -1 {
// There should be at least a digit.
return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
}
var num, sfx string
if sizeStr[sep] != ' ' {
num = sizeStr[:sep+1]
sfx = sizeStr[sep+1:]
} else {
// Omit the space separator.
num = sizeStr[:sep]
sfx = sizeStr[sep+1:]
}
size, err := strconv.ParseFloat(matches[1], 64)
size, err := strconv.ParseFloat(num, 64)
if err != nil {
return -1, err
}
// Backward compatibility: reject negative sizes.
if size < 0 {
return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
}
unitPrefix := strings.ToLower(matches[3])
if mul, ok := uMap[unitPrefix]; ok {
if len(sfx) == 0 {
return int64(size), nil
}
// Process the suffix.
if len(sfx) > 3 { // Too long.
goto badSuffix
}
sfx = strings.ToLower(sfx)
// Trivial case: b suffix.
if sfx[0] == 'b' {
if len(sfx) > 1 { // no extra characters allowed after b.
goto badSuffix
}
return int64(size), nil
}
// A suffix from the map.
if mul, ok := uMap[sfx[0]]; ok {
size *= float64(mul)
} else {
goto badSuffix
}
// The suffix may have extra "b" or "ib" (e.g. KiB or MB).
switch {
case len(sfx) == 2 && sfx[1] != 'b':
goto badSuffix
case len(sfx) == 3 && sfx[1:] != "ib":
goto badSuffix
}
return int64(size), nil
badSuffix:
return -1, fmt.Errorf("invalid suffix: '%s'", sfx)
}