vendor: github.com/containerd/containerd v1.6.22

- full diff: https://github.com/containerd/containerd/compare/v1.6.21...v1.6.22
- release notes: https://github.com/containerd/containerd/releases/tag/v1.6.22

---

Notable Updates

- RunC: Update runc binary to v1.1.8
- CRI: Fix `additionalGids`: it should fallback to `imageConfig.User`
  when `securityContext.RunAsUser`, `RunAsUsername` are empty
- CRI: Write generated CNI config atomically
- Fix concurrent writes for `UpdateContainerStats`
- Make `checkContainerTimestamps` less strict on Windows
- Port-Forward: Correctly handle known errors
- Resolve `docker.NewResolver` race condition
- SecComp: Always allow `name_to_handle_at`
- Adding support to run hcsshim from local clone
- Pinned image support
- Runtime/V2/RunC: Handle early exits w/o big locks
- CRITool: Move up to CRI-TOOLS v1.27.0
- Fix cpu architecture detection issue on emulated ARM platform
- Task: Don't `close()` io before `cancel()`
- Fix panic when remote differ returns empty result
- Plugins: Notify readiness when registered plugins are ready
- Unwrap io errors in server connection receive error handling

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2023-07-29 19:54:59 +02:00
parent 935c04f33a
commit 4d674897f3
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
18 changed files with 492 additions and 138 deletions

View file

@ -26,7 +26,7 @@ require (
github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5
github.com/container-orchestrated-devices/container-device-interface v0.6.0
github.com/containerd/cgroups/v3 v3.0.2
github.com/containerd/containerd v1.6.21
github.com/containerd/containerd v1.6.22
github.com/containerd/continuity v0.4.1
github.com/containerd/fifo v1.1.0
github.com/containerd/typeurl/v2 v2.1.1

View file

@ -357,8 +357,8 @@ github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09Zvgq
github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
github.com/containerd/containerd v1.6.21 h1:eSTAmnvDKRPWan+MpSSfNyrtleXd86ogK9X8fMWpe/Q=
github.com/containerd/containerd v1.6.21/go.mod h1:apei1/i5Ux2FzrK6+DM/suEsGuK/MeVOfy8tR2q7Wnw=
github.com/containerd/containerd v1.6.22 h1:rGTIBxPJusM0evF6wKgIzuD+tV70nmx9eEjzHVm1JzI=
github.com/containerd/containerd v1.6.22/go.mod h1:BQAJdahvGz8xboAvxKg9hsDYIovn79Ea318anowQ1/o=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=

View file

@ -145,3 +145,5 @@ Zhoulin Xie <zhoulin.xie@daocloud.io>
Zhoulin Xie <zhoulin.xie@daocloud.io> <42261994+JoeWrightss@users.noreply.github.com>
zounengren <zouyee1989@gmail.com> <zounengren@cmss.chinamobile.com>
张潇 <xiaozhang0210@hotmail.com>
Kazuyoshi Kato <kaz@fly.io> <katokazu@amazon.com>
Andrey Epifanov <epifanov.andrey@gmail.com> <aepifanov@mirantis.com>

View file

@ -332,22 +332,26 @@ install-cri-deps: $(BINARIES)
@$(INSTALL) $(BINARIES) $(CRIDIR)/bin
endif
$(CRIDIR)/cri-containerd.DEPRECATED.txt:
@mkdir -p $(CRIDIR)
@$(INSTALL) -m 644 releases/cri-containerd.DEPRECATED.txt $@
ifeq ($(GOOS),windows)
releases/$(CRIRELEASE).tar.gz: install-cri-deps
releases/$(CRIRELEASE).tar.gz: install-cri-deps $(CRIDIR)/cri-containerd.DEPRECATED.txt
@echo "$(WHALE) $@"
@cd $(CRIDIR) && tar -czf ../../releases/$(CRIRELEASE).tar.gz *
releases/$(CRICNIRELEASE).tar.gz: install-cri-deps
releases/$(CRICNIRELEASE).tar.gz: install-cri-deps $(CRIDIR)/cri-containerd.DEPRECATED.txt
@echo "$(WHALE) $@"
@cd $(CRIDIR) && tar -czf ../../releases/$(CRICNIRELEASE).tar.gz *
else
releases/$(CRIRELEASE).tar.gz: install-cri-deps
releases/$(CRIRELEASE).tar.gz: install-cri-deps $(CRIDIR)/cri-containerd.DEPRECATED.txt
@echo "$(WHALE) $@"
@tar -czf releases/$(CRIRELEASE).tar.gz -C $(CRIDIR) etc/crictl.yaml etc/systemd usr opt/containerd
@tar -czf releases/$(CRIRELEASE).tar.gz -C $(CRIDIR) cri-containerd.DEPRECATED.txt etc/crictl.yaml etc/systemd usr opt/containerd
releases/$(CRICNIRELEASE).tar.gz: install-cri-deps
releases/$(CRICNIRELEASE).tar.gz: install-cri-deps $(CRIDIR)/cri-containerd.DEPRECATED.txt
@echo "$(WHALE) $@"
@tar -czf releases/$(CRICNIRELEASE).tar.gz -C $(CRIDIR) etc usr opt
@tar -czf releases/$(CRICNIRELEASE).tar.gz -C $(CRIDIR) cri-containerd.DEPRECATED.txt etc usr opt
endif
cri-release: releases/$(CRIRELEASE).tar.gz

View file

@ -93,7 +93,7 @@ EOF
config.vm.provision "install-golang", type: "shell", run: "once" do |sh|
sh.upload_path = "/tmp/vagrant-install-golang"
sh.env = {
'GO_VERSION': ENV['GO_VERSION'] || "1.19.9",
'GO_VERSION': ENV['GO_VERSION'] || "1.19.11",
}
sh.inline = <<~SHELL
#!/usr/bin/env bash

View file

@ -86,6 +86,9 @@ func (r *diffRemote) Compare(ctx context.Context, a, b []mount.Mount, opts ...di
}
func toDescriptor(d *types.Descriptor) ocispec.Descriptor {
if d == nil {
return ocispec.Descriptor{}
}
return ocispec.Descriptor{
MediaType: d.MediaType,
Digest: d.Digest,

View file

@ -18,6 +18,7 @@ package log
import (
"context"
"fmt"
"github.com/sirupsen/logrus"
)
@ -35,6 +36,12 @@ var (
type (
loggerKey struct{}
// Fields type to pass to `WithFields`, alias from `logrus`.
Fields = logrus.Fields
// Level is a logging level
Level = logrus.Level
)
const (
@ -47,8 +54,52 @@ const (
// JSONFormat represents the JSON logging format
JSONFormat = "json"
// TraceLevel level.
TraceLevel = logrus.TraceLevel
// DebugLevel level.
DebugLevel = logrus.DebugLevel
// InfoLevel level.
InfoLevel = logrus.InfoLevel
)
// SetLevel sets log level globally.
func SetLevel(level string) error {
lvl, err := logrus.ParseLevel(level)
if err != nil {
return err
}
logrus.SetLevel(lvl)
return nil
}
// GetLevel returns the current log level.
func GetLevel() Level {
return logrus.GetLevel()
}
// SetFormat sets log output format
func SetFormat(format string) error {
switch format {
case TextFormat:
logrus.SetFormatter(&logrus.TextFormatter{
TimestampFormat: RFC3339NanoFixed,
FullTimestamp: true,
})
case JSONFormat:
logrus.SetFormatter(&logrus.JSONFormatter{
TimestampFormat: RFC3339NanoFixed,
})
default:
return fmt.Errorf("unknown log format: %s", format)
}
return nil
}
// WithLogger returns a new context with the provided logger. Use in
// combination with logger.WithField(s) for great effect.
func WithLogger(ctx context.Context, logger *logrus.Entry) context.Context {

View file

@ -0,0 +1,148 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Package atomicfile provides a mechanism (on Unix-like platforms) to present a consistent view of a file to separate
processes even while the file is being written. This is accomplished by writing a temporary file, syncing to disk, and
renaming over the destination file name.
Partial/inconsistent reads can occur due to:
1. A process attempting to read the file while it is being written to (both in the case of a new file with a
short/incomplete write or in the case of an existing, updated file where new bytes may be written at the beginning
but old bytes may still be present after).
2. Concurrent goroutines leading to multiple active writers of the same file.
The above mechanism explicitly protects against (1) as all writes are to a file with a temporary name.
There is no explicit protection against multiple, concurrent goroutines attempting to write the same file. However,
atomically writing the file should mean only one writer will "win" and a consistent file will be visible.
Note: atomicfile is partially implemented for Windows. The Windows codepath performs the same operations, however
Windows does not guarantee that a rename operation is atomic; a crash in the middle may leave the destination file
truncated rather than with the expected content.
*/
package atomicfile
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"sync"
)
// File is an io.ReadWriteCloser that can also be Canceled if a change needs to be abandoned.
type File interface {
io.ReadWriteCloser
// Cancel abandons a change to a file. This can be called if a write fails or another error occurs.
Cancel() error
}
// ErrClosed is returned if Read or Write are called on a closed File.
var ErrClosed = errors.New("file is closed")
// New returns a new atomic file. On Unix-like platforms, the writer (an io.ReadWriteCloser) is backed by a temporary
// file placed into the same directory as the destination file (using filepath.Dir to split the directory from the
// name). On a call to Close the temporary file is synced to disk and renamed to its final name, hiding any previous
// file by the same name.
//
// Note: Take care to call Close and handle any errors that are returned. Errors returned from Close may indicate that
// the file was not written with its final name.
func New(name string, mode os.FileMode) (File, error) {
return newFile(name, mode)
}
type atomicFile struct {
name string
f *os.File
closed bool
closedMu sync.RWMutex
}
func newFile(name string, mode os.FileMode) (File, error) {
dir := filepath.Dir(name)
f, err := os.CreateTemp(dir, "")
if err != nil {
return nil, fmt.Errorf("failed to create temp file: %w", err)
}
if err := f.Chmod(mode); err != nil {
return nil, fmt.Errorf("failed to change temp file permissions: %w", err)
}
return &atomicFile{name: name, f: f}, nil
}
func (a *atomicFile) Close() (err error) {
a.closedMu.Lock()
defer a.closedMu.Unlock()
if a.closed {
return nil
}
a.closed = true
defer func() {
if err != nil {
_ = os.Remove(a.f.Name()) // ignore errors
}
}()
// The order of operations here is:
// 1. sync
// 2. close
// 3. rename
// While the ordering of 2 and 3 is not important on Unix-like operating systems, Windows cannot rename an open
// file. By closing first, we allow the rename operation to succeed.
if err = a.f.Sync(); err != nil {
return fmt.Errorf("failed to sync temp file %q: %w", a.f.Name(), err)
}
if err = a.f.Close(); err != nil {
return fmt.Errorf("failed to close temp file %q: %w", a.f.Name(), err)
}
if err = os.Rename(a.f.Name(), a.name); err != nil {
return fmt.Errorf("failed to rename %q to %q: %w", a.f.Name(), a.name, err)
}
return nil
}
func (a *atomicFile) Cancel() error {
a.closedMu.Lock()
defer a.closedMu.Unlock()
if a.closed {
return nil
}
a.closed = true
_ = a.f.Close() // ignore error
return os.Remove(a.f.Name())
}
func (a *atomicFile) Read(p []byte) (n int, err error) {
a.closedMu.RLock()
defer a.closedMu.RUnlock()
if a.closed {
return 0, ErrClosed
}
return a.f.Read(p)
}
func (a *atomicFile) Write(p []byte) (n int, err error) {
a.closedMu.RLock()
defer a.closedMu.RUnlock()
if a.closed {
return 0, ErrClosed
}
return a.f.Write(p)
}

View file

@ -17,14 +17,9 @@
package platforms
import (
"bufio"
"fmt"
"os"
"runtime"
"strings"
"sync"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/log"
)
@ -37,95 +32,12 @@ var cpuVariantOnce sync.Once
func cpuVariant() string {
cpuVariantOnce.Do(func() {
if isArmArch(runtime.GOARCH) {
cpuVariantValue = getCPUVariant()
var err error
cpuVariantValue, err = getCPUVariant()
if err != nil {
log.L.Errorf("Error getCPUVariant for OS %s: %v", runtime.GOOS, err)
}
}
})
return cpuVariantValue
}
// For Linux, the kernel has already detected the ABI, ISA and Features.
// So we don't need to access the ARM registers to detect platform information
// by ourselves. We can just parse these information from /proc/cpuinfo
func getCPUInfo(pattern string) (info string, err error) {
if !isLinuxOS(runtime.GOOS) {
return "", fmt.Errorf("getCPUInfo for OS %s: %w", runtime.GOOS, errdefs.ErrNotImplemented)
}
cpuinfo, err := os.Open("/proc/cpuinfo")
if err != nil {
return "", err
}
defer cpuinfo.Close()
// Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
// the first core is enough.
scanner := bufio.NewScanner(cpuinfo)
for scanner.Scan() {
newline := scanner.Text()
list := strings.Split(newline, ":")
if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
return strings.TrimSpace(list[1]), nil
}
}
// Check whether the scanner encountered errors
err = scanner.Err()
if err != nil {
return "", err
}
return "", fmt.Errorf("getCPUInfo for pattern: %s: %w", pattern, errdefs.ErrNotFound)
}
func getCPUVariant() string {
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
// Windows/Darwin only supports v7 for ARM32 and v8 for ARM64 and so we can use
// runtime.GOARCH to determine the variants
var variant string
switch runtime.GOARCH {
case "arm64":
variant = "v8"
case "arm":
variant = "v7"
default:
variant = "unknown"
}
return variant
}
variant, err := getCPUInfo("Cpu architecture")
if err != nil {
log.L.WithError(err).Error("failure getting variant")
return ""
}
// handle edge case for Raspberry Pi ARMv6 devices (which due to a kernel quirk, report "CPU architecture: 7")
// https://www.raspberrypi.org/forums/viewtopic.php?t=12614
if runtime.GOARCH == "arm" && variant == "7" {
model, err := getCPUInfo("model name")
if err == nil && strings.HasPrefix(strings.ToLower(model), "armv6-compatible") {
variant = "6"
}
}
switch strings.ToLower(variant) {
case "8", "aarch64":
variant = "v8"
case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
variant = "v7"
case "6", "6tej":
variant = "v6"
case "5", "5t", "5te", "5tej":
variant = "v5"
case "4", "4t":
variant = "v4"
case "3":
variant = "v3"
default:
variant = "unknown"
}
return variant
}

View file

@ -0,0 +1,161 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package platforms
import (
"bufio"
"bytes"
"fmt"
"os"
"runtime"
"strings"
"github.com/containerd/containerd/errdefs"
"golang.org/x/sys/unix"
)
// getMachineArch retrieves the machine architecture through system call
func getMachineArch() (string, error) {
var uname unix.Utsname
err := unix.Uname(&uname)
if err != nil {
return "", err
}
arch := string(uname.Machine[:bytes.IndexByte(uname.Machine[:], 0)])
return arch, nil
}
// For Linux, the kernel has already detected the ABI, ISA and Features.
// So we don't need to access the ARM registers to detect platform information
// by ourselves. We can just parse these information from /proc/cpuinfo
func getCPUInfo(pattern string) (info string, err error) {
cpuinfo, err := os.Open("/proc/cpuinfo")
if err != nil {
return "", err
}
defer cpuinfo.Close()
// Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
// the first core is enough.
scanner := bufio.NewScanner(cpuinfo)
for scanner.Scan() {
newline := scanner.Text()
list := strings.Split(newline, ":")
if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
return strings.TrimSpace(list[1]), nil
}
}
// Check whether the scanner encountered errors
err = scanner.Err()
if err != nil {
return "", err
}
return "", fmt.Errorf("getCPUInfo for pattern %s: %w", pattern, errdefs.ErrNotFound)
}
// getCPUVariantFromArch get CPU variant from arch through a system call
func getCPUVariantFromArch(arch string) (string, error) {
var variant string
arch = strings.ToLower(arch)
if arch == "aarch64" {
variant = "8"
} else if arch[0:4] == "armv" && len(arch) >= 5 {
//Valid arch format is in form of armvXx
switch arch[3:5] {
case "v8":
variant = "8"
case "v7":
variant = "7"
case "v6":
variant = "6"
case "v5":
variant = "5"
case "v4":
variant = "4"
case "v3":
variant = "3"
default:
variant = "unknown"
}
} else {
return "", fmt.Errorf("getCPUVariantFromArch invalid arch: %s, %w", arch, errdefs.ErrInvalidArgument)
}
return variant, nil
}
// getCPUVariant returns cpu variant for ARM
// We first try reading "Cpu architecture" field from /proc/cpuinfo
// If we can't find it, then fall back using a system call
// This is to cover running ARM in emulated environment on x86 host as this field in /proc/cpuinfo
// was not present.
func getCPUVariant() (string, error) {
variant, err := getCPUInfo("Cpu architecture")
if err != nil {
if errdefs.IsNotFound(err) {
//Let's try getting CPU variant from machine architecture
arch, err := getMachineArch()
if err != nil {
return "", fmt.Errorf("failure getting machine architecture: %v", err)
}
variant, err = getCPUVariantFromArch(arch)
if err != nil {
return "", fmt.Errorf("failure getting CPU variant from machine architecture: %v", err)
}
} else {
return "", fmt.Errorf("failure getting CPU variant: %v", err)
}
}
// handle edge case for Raspberry Pi ARMv6 devices (which due to a kernel quirk, report "CPU architecture: 7")
// https://www.raspberrypi.org/forums/viewtopic.php?t=12614
if runtime.GOARCH == "arm" && variant == "7" {
model, err := getCPUInfo("model name")
if err == nil && strings.HasPrefix(strings.ToLower(model), "armv6-compatible") {
variant = "6"
}
}
switch strings.ToLower(variant) {
case "8", "aarch64":
variant = "v8"
case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
variant = "v7"
case "6", "6tej":
variant = "v6"
case "5", "5t", "5te", "5tej":
variant = "v5"
case "4", "4t":
variant = "v4"
case "3":
variant = "v3"
default:
variant = "unknown"
}
return variant, nil
}

View file

@ -0,0 +1,60 @@
//go:build !linux
// +build !linux
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package platforms
import (
"fmt"
"runtime"
"github.com/containerd/containerd/errdefs"
)
func getCPUVariant() (string, error) {
var variant string
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
// Windows/Darwin only supports v7 for ARM32 and v8 for ARM64 and so we can use
// runtime.GOARCH to determine the variants
switch runtime.GOARCH {
case "arm64":
variant = "v8"
case "arm":
variant = "v7"
default:
variant = "unknown"
}
} else if runtime.GOOS == "freebsd" {
// FreeBSD supports ARMv6 and ARMv7 as well as ARMv4 and ARMv5 (though deprecated)
// detecting those variants is currently unimplemented
switch runtime.GOARCH {
case "arm64":
variant = "v8"
default:
variant = "unknown"
}
} else {
return "", fmt.Errorf("getCPUVariant for OS %s: %v", runtime.GOOS, errdefs.ErrNotImplemented)
}
return variant, nil
}

View file

@ -21,13 +21,6 @@ import (
"strings"
)
// isLinuxOS returns true if the operating system is Linux.
//
// The OS value should be normalized before calling this function.
func isLinuxOS(os string) bool {
return os == "linux"
}
// These function are generated from https://golang.org/src/go/build/syslist.go.
//
// We use switch statements because they are slightly faster than map lookups

View file

@ -28,12 +28,13 @@ import (
// InitContext is used for plugin initialization
type InitContext struct {
Context context.Context
Root string
State string
Config interface{}
Address string
TTRPCAddress string
Context context.Context
Root string
State string
Config interface{}
Address string
TTRPCAddress string
RegisterReadiness func() func()
// deprecated: will be removed in 2.0, use plugin.EventType
Events *exchange.Exchange

View file

@ -95,25 +95,30 @@ type ResolverOptions struct {
Tracker StatusTracker
// Authorizer is used to authorize registry requests
// Deprecated: use Hosts
//
// Deprecated: use Hosts.
Authorizer Authorizer
// Credentials provides username and secret given a host.
// If username is empty but a secret is given, that secret
// is interpreted as a long lived token.
// Deprecated: use Hosts
//
// Deprecated: use Hosts.
Credentials func(string) (string, string, error)
// Host provides the hostname given a namespace.
// Deprecated: use Hosts
//
// Deprecated: use Hosts.
Host func(string) (string, error)
// PlainHTTP specifies to use plain http and not https
// Deprecated: use Hosts
//
// Deprecated: use Hosts.
PlainHTTP bool
// Client is the http client to used when making registry requests
// Deprecated: use Hosts
//
// Deprecated: use Hosts.
Client *http.Client
}
@ -140,6 +145,9 @@ func NewResolver(options ResolverOptions) remotes.Resolver {
if options.Headers == nil {
options.Headers = make(http.Header)
} else {
// make a copy of the headers to avoid race due to concurrent map write
options.Headers = options.Headers.Clone()
}
if _, ok := options.Headers["User-Agent"]; !ok {
options.Headers.Set("User-Agent", "containerd/"+version.Version)
@ -529,9 +537,10 @@ func (r *request) do(ctx context.Context) (*http.Response, error) {
if err != nil {
return nil, err
}
req.Header = http.Header{} // headers need to be copied to avoid concurrent map access
for k, v := range r.header {
req.Header[k] = v
if r.header == nil {
req.Header = http.Header{}
} else {
req.Header = r.header.Clone() // headers need to be copied to avoid concurrent map access
}
if r.body != nil {
body, err := r.body()

View file

@ -27,11 +27,13 @@ import (
"strings"
"time"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/ttrpc"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/types"
exec "golang.org/x/sys/execabs"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/pkg/atomicfile"
)
type CommandConfig struct {
@ -118,17 +120,16 @@ func WritePidFile(path string, pid int) error {
if err != nil {
return err
}
tempPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path)))
f, err := os.OpenFile(tempPath, os.O_RDWR|os.O_CREATE|os.O_EXCL|os.O_SYNC, 0666)
f, err := atomicfile.New(path, 0o666)
if err != nil {
return err
}
_, err = fmt.Fprintf(f, "%d", pid)
f.Close()
if err != nil {
f.Cancel()
return err
}
return os.Rename(tempPath, path)
return f.Close()
}
// WriteAddress writes a address file atomically
@ -137,17 +138,16 @@ func WriteAddress(path, address string) error {
if err != nil {
return err
}
tempPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path)))
f, err := os.OpenFile(tempPath, os.O_RDWR|os.O_CREATE|os.O_EXCL|os.O_SYNC, 0666)
f, err := atomicfile.New(path, 0o666)
if err != nil {
return err
}
_, err = f.WriteString(address)
f.Close()
_, err = f.Write([]byte(address))
if err != nil {
f.Cancel()
return err
}
return os.Rename(tempPath, path)
return f.Close()
}
// ErrNoAddress is returned when the address file has no content

View file

@ -325,7 +325,16 @@ func (t *task) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (*ExitStat
return nil, fmt.Errorf("task must be stopped before deletion: %s: %w", status.Status, errdefs.ErrFailedPrecondition)
}
if t.io != nil {
t.io.Close()
// io.Wait locks for restored tasks on Windows unless we call
// io.Close first (https://github.com/containerd/containerd/issues/5621)
// in other cases, preserve the contract and let IO finish before closing
if t.client.runtime == fmt.Sprintf("%s.%s", plugin.RuntimePlugin, "windows") {
t.io.Close()
}
// io.Cancel is used to cancel the io goroutine while it is in
// fifo-opening state. It does not stop the pipes since these
// should be closed on the shim's side, otherwise we might lose
// data from the container!
t.io.Cancel()
t.io.Wait()
}

View file

@ -23,7 +23,7 @@ var (
Package = "github.com/containerd/containerd"
// Version holds the complete version number. Filled in at linking time.
Version = "1.6.21+unknown"
Version = "1.6.22+unknown"
// Revision is filled with the VCS (e.g. git) revision being used to build
// the program at linking time.

5
vendor/modules.txt vendored
View file

@ -236,8 +236,8 @@ github.com/containerd/cgroups/v3/cgroup2/stats
# github.com/containerd/console v1.0.3
## explicit; go 1.13
github.com/containerd/console
# github.com/containerd/containerd v1.6.21
## explicit; go 1.17
# github.com/containerd/containerd v1.6.22
## explicit; go 1.18
github.com/containerd/containerd
github.com/containerd/containerd/api/events
github.com/containerd/containerd/api/services/containers/v1
@ -286,6 +286,7 @@ github.com/containerd/containerd/mount
github.com/containerd/containerd/namespaces
github.com/containerd/containerd/oci
github.com/containerd/containerd/pkg/apparmor
github.com/containerd/containerd/pkg/atomicfile
github.com/containerd/containerd/pkg/cap
github.com/containerd/containerd/pkg/dialer
github.com/containerd/containerd/pkg/kmutex