-
Notifications
You must be signed in to change notification settings - Fork 786
/
common.go
139 lines (131 loc) · 4.22 KB
/
common.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package buildah
import (
"context"
"io"
"net"
"net/url"
"os"
"path/filepath"
"syscall"
"time"
cp "github.com/containers/image/v5/copy"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/signature"
"github.com/containers/image/v5/types"
encconfig "github.com/containers/ocicrypt/config"
"github.com/containers/storage"
"github.com/containers/storage/pkg/unshare"
"github.com/docker/distribution/registry/api/errcode"
errcodev2 "github.com/docker/distribution/registry/api/v2"
multierror "github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
const (
// OCI used to define the "oci" image format
OCI = "oci"
// DOCKER used to define the "docker" image format
DOCKER = "docker"
)
func getCopyOptions(store storage.Store, reportWriter io.Writer, sourceSystemContext *types.SystemContext, destinationSystemContext *types.SystemContext, manifestType string, removeSignatures bool, addSigner string, ociEncryptLayers *[]int, ociEncryptConfig *encconfig.EncryptConfig, ociDecryptConfig *encconfig.DecryptConfig) *cp.Options {
sourceCtx := getSystemContext(store, nil, "")
if sourceSystemContext != nil {
*sourceCtx = *sourceSystemContext
}
destinationCtx := getSystemContext(store, nil, "")
if destinationSystemContext != nil {
*destinationCtx = *destinationSystemContext
}
return &cp.Options{
ReportWriter: reportWriter,
SourceCtx: sourceCtx,
DestinationCtx: destinationCtx,
ForceManifestMIMEType: manifestType,
RemoveSignatures: removeSignatures,
SignBy: addSigner,
OciEncryptConfig: ociEncryptConfig,
OciDecryptConfig: ociDecryptConfig,
OciEncryptLayers: ociEncryptLayers,
}
}
func getSystemContext(store storage.Store, defaults *types.SystemContext, signaturePolicyPath string) *types.SystemContext {
sc := &types.SystemContext{}
if defaults != nil {
*sc = *defaults
}
if signaturePolicyPath != "" {
sc.SignaturePolicyPath = signaturePolicyPath
}
if store != nil {
if sc.BlobInfoCacheDir == "" {
sc.BlobInfoCacheDir = filepath.Join(store.GraphRoot(), "cache")
}
if sc.SystemRegistriesConfPath == "" && unshare.IsRootless() {
userRegistriesFile := filepath.Join(store.GraphRoot(), "registries.conf")
if _, err := os.Stat(userRegistriesFile); err == nil {
sc.SystemRegistriesConfPath = userRegistriesFile
}
}
}
return sc
}
func isRetryable(err error) bool {
err = errors.Cause(err)
type unwrapper interface {
Unwrap() error
}
if unwrapper, ok := err.(unwrapper); ok {
err = unwrapper.Unwrap()
return isRetryable(err)
}
if registryError, ok := err.(errcode.Error); ok {
switch registryError.Code {
case errcode.ErrorCodeUnauthorized, errcodev2.ErrorCodeNameUnknown, errcodev2.ErrorCodeManifestUnknown:
return false
}
return true
}
if op, ok := err.(*net.OpError); ok {
return isRetryable(op.Err)
}
if url, ok := err.(*url.Error); ok {
return isRetryable(url.Err)
}
if errno, ok := err.(syscall.Errno); ok {
if errno == syscall.ECONNREFUSED {
return false
}
}
if errs, ok := err.(errcode.Errors); ok {
// if this error is a group of errors, process them all in turn
for i := range errs {
if !isRetryable(errs[i]) {
return false
}
}
}
if errs, ok := err.(*multierror.Error); ok {
// if this error is a group of errors, process them all in turn
for i := range errs.Errors {
if !isRetryable(errs.Errors[i]) {
return false
}
}
}
return true
}
func retryCopyImage(ctx context.Context, policyContext *signature.PolicyContext, dest, src, registry types.ImageReference, action string, copyOptions *cp.Options, maxRetries int, retryDelay time.Duration) ([]byte, error) {
manifestBytes, err := cp.Image(ctx, policyContext, dest, src, copyOptions)
for retries := 0; err != nil && isRetryable(err) && registry != nil && registry.Transport().Name() == docker.Transport.Name() && retries < maxRetries; retries++ {
if retryDelay == 0 {
retryDelay = 5 * time.Second
}
logrus.Infof("Warning: %s failed, retrying in %s ... (%d/%d)", action, retryDelay, retries+1, maxRetries)
time.Sleep(retryDelay)
manifestBytes, err = cp.Image(ctx, policyContext, dest, src, copyOptions)
if err == nil {
break
}
}
return manifestBytes, err
}