mirror of
https://github.com/containers/skopeo.git
synced 2025-07-18 08:41:41 +00:00
fix inspect with nil image config
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
parent
5436111796
commit
e3f7733de1
210
vendor/github.com/containers/image/docker/docker_client.go
generated
vendored
210
vendor/github.com/containers/image/docker/docker_client.go
generated
vendored
@ -3,23 +3,20 @@ package docker
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containers/image/docker/reference"
|
"github.com/containers/image/docker/reference"
|
||||||
|
"github.com/containers/image/pkg/docker/config"
|
||||||
"github.com/containers/image/pkg/tlsclientconfig"
|
"github.com/containers/image/pkg/tlsclientconfig"
|
||||||
"github.com/containers/image/types"
|
"github.com/containers/image/types"
|
||||||
"github.com/containers/storage/pkg/homedir"
|
|
||||||
"github.com/docker/distribution/registry/client"
|
"github.com/docker/distribution/registry/client"
|
||||||
helperclient "github.com/docker/docker-credential-helpers/client"
|
|
||||||
"github.com/docker/go-connections/tlsconfig"
|
"github.com/docker/go-connections/tlsconfig"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -29,11 +26,6 @@ import (
|
|||||||
const (
|
const (
|
||||||
dockerHostname = "docker.io"
|
dockerHostname = "docker.io"
|
||||||
dockerRegistry = "registry-1.docker.io"
|
dockerRegistry = "registry-1.docker.io"
|
||||||
dockerAuthRegistry = "https://index.docker.io/v1/"
|
|
||||||
|
|
||||||
dockerCfg = ".docker"
|
|
||||||
dockerCfgFileName = "config.json"
|
|
||||||
dockerCfgObsolete = ".dockercfg"
|
|
||||||
|
|
||||||
systemPerHostCertDirPath = "/etc/docker/certs.d"
|
systemPerHostCertDirPath = "/etc/docker/certs.d"
|
||||||
|
|
||||||
@ -51,9 +43,13 @@ const (
|
|||||||
extensionSignatureTypeAtomic = "atomic" // extensionSignature.Type
|
extensionSignatureTypeAtomic = "atomic" // extensionSignature.Type
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrV1NotSupported is returned when we're trying to talk to a
|
var (
|
||||||
// docker V1 registry.
|
// ErrV1NotSupported is returned when we're trying to talk to a
|
||||||
var ErrV1NotSupported = errors.New("can't talk to a V1 docker registry")
|
// docker V1 registry.
|
||||||
|
ErrV1NotSupported = errors.New("can't talk to a V1 docker registry")
|
||||||
|
// ErrUnauthorizedForCredentials is returned when the status code returned is 401
|
||||||
|
ErrUnauthorizedForCredentials = errors.New("unable to retrieve auth token: invalid username/password")
|
||||||
|
)
|
||||||
|
|
||||||
// extensionSignature and extensionSignatureList come from github.com/openshift/origin/pkg/dockerregistry/server/signaturedispatcher.go:
|
// extensionSignature and extensionSignatureList come from github.com/openshift/origin/pkg/dockerregistry/server/signaturedispatcher.go:
|
||||||
// signature represents a Docker image signature.
|
// signature represents a Docker image signature.
|
||||||
@ -128,52 +124,84 @@ func dockerCertDir(ctx *types.SystemContext, hostPort string) string {
|
|||||||
return filepath.Join(hostCertDir, hostPort)
|
return filepath.Join(hostCertDir, hostPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newDockerClient returns a new dockerClient instance for refHostname (a host a specified in the Docker image reference, not canonicalized to dockerRegistry)
|
// newDockerClientFromRef returns a new dockerClient instance for refHostname (a host a specified in the Docker image reference, not canonicalized to dockerRegistry)
|
||||||
// “write” specifies whether the client will be used for "write" access (in particular passed to lookaside.go:toplevelFromSection)
|
// “write” specifies whether the client will be used for "write" access (in particular passed to lookaside.go:toplevelFromSection)
|
||||||
func newDockerClient(ctx *types.SystemContext, ref dockerReference, write bool, actions string) (*dockerClient, error) {
|
func newDockerClientFromRef(ctx *types.SystemContext, ref dockerReference, write bool, actions string) (*dockerClient, error) {
|
||||||
registry := reference.Domain(ref.ref)
|
registry := reference.Domain(ref.ref)
|
||||||
if registry == dockerHostname {
|
username, password, err := config.GetAuthentication(ctx, reference.Domain(ref.ref))
|
||||||
registry = dockerRegistry
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error getting username and password")
|
||||||
}
|
}
|
||||||
username, password, err := getAuth(ctx, reference.Domain(ref.ref))
|
sigBase, err := configuredSignatureStorageBase(ctx, ref, write)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
remoteName := reference.Path(ref.ref)
|
||||||
|
|
||||||
|
return newDockerClientWithDetails(ctx, registry, username, password, actions, sigBase, remoteName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newDockerClientWithDetails returns a new dockerClient instance for the given parameters
|
||||||
|
func newDockerClientWithDetails(ctx *types.SystemContext, registry, username, password, actions string, sigBase signatureStorageBase, remoteName string) (*dockerClient, error) {
|
||||||
|
hostName := registry
|
||||||
|
if registry == dockerHostname {
|
||||||
|
registry = dockerRegistry
|
||||||
|
}
|
||||||
tr := tlsclientconfig.NewTransport()
|
tr := tlsclientconfig.NewTransport()
|
||||||
tr.TLSClientConfig = serverDefault()
|
tr.TLSClientConfig = serverDefault()
|
||||||
|
|
||||||
// It is undefined whether the host[:port] string for dockerHostname should be dockerHostname or dockerRegistry,
|
// It is undefined whether the host[:port] string for dockerHostname should be dockerHostname or dockerRegistry,
|
||||||
// because docker/docker does not read the certs.d subdirectory at all in that case. We use the user-visible
|
// because docker/docker does not read the certs.d subdirectory at all in that case. We use the user-visible
|
||||||
// dockerHostname here, because it is more symmetrical to read the configuration in that case as well, and because
|
// dockerHostname here, because it is more symmetrical to read the configuration in that case as well, and because
|
||||||
// generally the UI hides the existence of the different dockerRegistry. But note that this behavior is
|
// generally the UI hides the existence of the different dockerRegistry. But note that this behavior is
|
||||||
// undocumented and may change if docker/docker changes.
|
// undocumented and may change if docker/docker changes.
|
||||||
certDir := dockerCertDir(ctx, reference.Domain(ref.ref))
|
certDir := dockerCertDir(ctx, hostName)
|
||||||
if err := tlsclientconfig.SetupCertificates(certDir, tr.TLSClientConfig); err != nil {
|
if err := tlsclientconfig.SetupCertificates(certDir, tr.TLSClientConfig); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx != nil && ctx.DockerInsecureSkipTLSVerify {
|
if ctx != nil && ctx.DockerInsecureSkipTLSVerify {
|
||||||
tr.TLSClientConfig.InsecureSkipVerify = true
|
tr.TLSClientConfig.InsecureSkipVerify = true
|
||||||
}
|
}
|
||||||
client := &http.Client{Transport: tr}
|
|
||||||
|
|
||||||
sigBase, err := configuredSignatureStorageBase(ctx, ref, write)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dockerClient{
|
return &dockerClient{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
registry: registry,
|
registry: registry,
|
||||||
username: username,
|
username: username,
|
||||||
password: password,
|
password: password,
|
||||||
client: client,
|
client: &http.Client{Transport: tr},
|
||||||
signatureBase: sigBase,
|
signatureBase: sigBase,
|
||||||
scope: authScope{
|
scope: authScope{
|
||||||
actions: actions,
|
actions: actions,
|
||||||
remoteName: reference.Path(ref.ref),
|
remoteName: remoteName,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckAuth validates the credentials by attempting to log into the registry
|
||||||
|
// returns an error if an error occcured while making the http request or the status code received was 401
|
||||||
|
func CheckAuth(ctx context.Context, sCtx *types.SystemContext, username, password, registry string) error {
|
||||||
|
newLoginClient, err := newDockerClientWithDetails(sCtx, registry, username, password, "", nil, "")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error creating new docker client")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := newLoginClient.makeRequest(ctx, "GET", "/v2/", nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
switch resp.StatusCode {
|
||||||
|
case http.StatusOK:
|
||||||
|
return nil
|
||||||
|
case http.StatusUnauthorized:
|
||||||
|
return ErrUnauthorizedForCredentials
|
||||||
|
default:
|
||||||
|
return errors.Errorf("error occured with status code %q", resp.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// makeRequest creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
|
// makeRequest creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
|
||||||
// The host name and schema is taken from the client or autodetected, and the path is relative to it, i.e. the path usually starts with /v2/.
|
// The host name and schema is taken from the client or autodetected, and the path is relative to it, i.e. the path usually starts with /v2/.
|
||||||
func (c *dockerClient) makeRequest(ctx context.Context, method, path string, headers map[string][]string, stream io.Reader) (*http.Response, error) {
|
func (c *dockerClient) makeRequest(ctx context.Context, method, path string, headers map[string][]string, stream io.Reader) (*http.Response, error) {
|
||||||
@ -245,7 +273,10 @@ func (c *dockerClient) setupRequestAuth(req *http.Request) error {
|
|||||||
return errors.Errorf("missing realm in bearer auth challenge")
|
return errors.Errorf("missing realm in bearer auth challenge")
|
||||||
}
|
}
|
||||||
service, _ := challenge.Parameters["service"] // Will be "" if not present
|
service, _ := challenge.Parameters["service"] // Will be "" if not present
|
||||||
scope := fmt.Sprintf("repository:%s:%s", c.scope.remoteName, c.scope.actions)
|
var scope string
|
||||||
|
if c.scope.remoteName != "" && c.scope.actions != "" {
|
||||||
|
scope = fmt.Sprintf("repository:%s:%s", c.scope.remoteName, c.scope.actions)
|
||||||
|
}
|
||||||
token, err := c.getBearerToken(req.Context(), realm, service, scope)
|
token, err := c.getBearerToken(req.Context(), realm, service, scope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -291,7 +322,7 @@ func (c *dockerClient) getBearerToken(ctx context.Context, realm, service, scope
|
|||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
switch res.StatusCode {
|
switch res.StatusCode {
|
||||||
case http.StatusUnauthorized:
|
case http.StatusUnauthorized:
|
||||||
return nil, errors.Errorf("unable to retrieve auth token: 401 unauthorized")
|
return nil, ErrUnauthorizedForCredentials
|
||||||
case http.StatusOK:
|
case http.StatusOK:
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
@ -315,65 +346,6 @@ func (c *dockerClient) getBearerToken(ctx context.Context, realm, service, scope
|
|||||||
return &token, nil
|
return &token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAuth(ctx *types.SystemContext, registry string) (string, string, error) {
|
|
||||||
if ctx != nil && ctx.DockerAuthConfig != nil {
|
|
||||||
return ctx.DockerAuthConfig.Username, ctx.DockerAuthConfig.Password, nil
|
|
||||||
}
|
|
||||||
var dockerAuth dockerConfigFile
|
|
||||||
dockerCfgPath := filepath.Join(getDefaultConfigDir(".docker"), dockerCfgFileName)
|
|
||||||
if _, err := os.Stat(dockerCfgPath); err == nil {
|
|
||||||
j, err := ioutil.ReadFile(dockerCfgPath)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(j, &dockerAuth); err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if os.IsNotExist(err) {
|
|
||||||
// try old config path
|
|
||||||
oldDockerCfgPath := filepath.Join(getDefaultConfigDir(dockerCfgObsolete))
|
|
||||||
if _, err := os.Stat(oldDockerCfgPath); err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return "", "", nil
|
|
||||||
}
|
|
||||||
return "", "", errors.Wrap(err, oldDockerCfgPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
j, err := ioutil.ReadFile(oldDockerCfgPath)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(j, &dockerAuth.AuthConfigs); err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if err != nil {
|
|
||||||
return "", "", errors.Wrap(err, dockerCfgPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// First try cred helpers. They should always be normalized.
|
|
||||||
if ch, exists := dockerAuth.CredHelpers[registry]; exists {
|
|
||||||
return getAuthFromCredHelper(ch, registry)
|
|
||||||
}
|
|
||||||
|
|
||||||
// I'm feeling lucky.
|
|
||||||
if c, exists := dockerAuth.AuthConfigs[registry]; exists {
|
|
||||||
return decodeDockerAuth(c.Auth)
|
|
||||||
}
|
|
||||||
|
|
||||||
// bad luck; let's normalize the entries first
|
|
||||||
registry = normalizeRegistry(registry)
|
|
||||||
normalizedAuths := map[string]dockerAuthConfig{}
|
|
||||||
for k, v := range dockerAuth.AuthConfigs {
|
|
||||||
normalizedAuths[normalizeRegistry(k)] = v
|
|
||||||
}
|
|
||||||
if c, exists := normalizedAuths[registry]; exists {
|
|
||||||
return decodeDockerAuth(c.Auth)
|
|
||||||
}
|
|
||||||
return "", "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// detectProperties detects various properties of the registry.
|
// detectProperties detects various properties of the registry.
|
||||||
// See the dockerClient documentation for members which are affected by this.
|
// See the dockerClient documentation for members which are affected by this.
|
||||||
func (c *dockerClient) detectProperties(ctx context.Context) error {
|
func (c *dockerClient) detectProperties(ctx context.Context) error {
|
||||||
@ -456,67 +428,3 @@ func (c *dockerClient) getExtensionsSignatures(ctx context.Context, ref dockerRe
|
|||||||
}
|
}
|
||||||
return &parsedBody, nil
|
return &parsedBody, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDefaultConfigDir(confPath string) string {
|
|
||||||
return filepath.Join(homedir.Get(), confPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
type dockerAuthConfig struct {
|
|
||||||
Auth string `json:"auth,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type dockerConfigFile struct {
|
|
||||||
AuthConfigs map[string]dockerAuthConfig `json:"auths"`
|
|
||||||
CredHelpers map[string]string `json:"credHelpers,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAuthFromCredHelper(credHelper, registry string) (string, string, error) {
|
|
||||||
helperName := fmt.Sprintf("docker-credential-%s", credHelper)
|
|
||||||
p := helperclient.NewShellProgramFunc(helperName)
|
|
||||||
creds, err := helperclient.Get(p, registry)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return creds.Username, creds.Secret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeDockerAuth(s string) (string, string, error) {
|
|
||||||
decoded, err := base64.StdEncoding.DecodeString(s)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
parts := strings.SplitN(string(decoded), ":", 2)
|
|
||||||
if len(parts) != 2 {
|
|
||||||
// if it's invalid just skip, as docker does
|
|
||||||
return "", "", nil
|
|
||||||
}
|
|
||||||
user := parts[0]
|
|
||||||
password := strings.Trim(parts[1], "\x00")
|
|
||||||
return user, password, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// convertToHostname converts a registry url which has http|https prepended
|
|
||||||
// to just an hostname.
|
|
||||||
// Copied from github.com/docker/docker/registry/auth.go
|
|
||||||
func convertToHostname(url string) string {
|
|
||||||
stripped := url
|
|
||||||
if strings.HasPrefix(url, "http://") {
|
|
||||||
stripped = strings.TrimPrefix(url, "http://")
|
|
||||||
} else if strings.HasPrefix(url, "https://") {
|
|
||||||
stripped = strings.TrimPrefix(url, "https://")
|
|
||||||
}
|
|
||||||
|
|
||||||
nameParts := strings.SplitN(stripped, "/", 2)
|
|
||||||
|
|
||||||
return nameParts[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalizeRegistry(registry string) string {
|
|
||||||
normalized := convertToHostname(registry)
|
|
||||||
switch normalized {
|
|
||||||
case "registry-1.docker.io", "docker.io":
|
|
||||||
return "index.docker.io"
|
|
||||||
}
|
|
||||||
return normalized
|
|
||||||
}
|
|
||||||
|
2
vendor/github.com/containers/image/docker/docker_image_dest.go
generated
vendored
2
vendor/github.com/containers/image/docker/docker_image_dest.go
generated
vendored
@ -34,7 +34,7 @@ type dockerImageDestination struct {
|
|||||||
|
|
||||||
// newImageDestination creates a new ImageDestination for the specified image reference.
|
// newImageDestination creates a new ImageDestination for the specified image reference.
|
||||||
func newImageDestination(ctx *types.SystemContext, ref dockerReference) (types.ImageDestination, error) {
|
func newImageDestination(ctx *types.SystemContext, ref dockerReference) (types.ImageDestination, error) {
|
||||||
c, err := newDockerClient(ctx, ref, true, "pull,push")
|
c, err := newDockerClientFromRef(ctx, ref, true, "pull,push")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
4
vendor/github.com/containers/image/docker/docker_image_src.go
generated
vendored
4
vendor/github.com/containers/image/docker/docker_image_src.go
generated
vendored
@ -31,7 +31,7 @@ type dockerImageSource struct {
|
|||||||
// newImageSource creates a new ImageSource for the specified image reference.
|
// newImageSource creates a new ImageSource for the specified image reference.
|
||||||
// The caller must call .Close() on the returned ImageSource.
|
// The caller must call .Close() on the returned ImageSource.
|
||||||
func newImageSource(ctx *types.SystemContext, ref dockerReference) (*dockerImageSource, error) {
|
func newImageSource(ctx *types.SystemContext, ref dockerReference) (*dockerImageSource, error) {
|
||||||
c, err := newDockerClient(ctx, ref, false, "pull")
|
c, err := newDockerClientFromRef(ctx, ref, false, "pull")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -298,7 +298,7 @@ func (s *dockerImageSource) getSignaturesFromAPIExtension(ctx context.Context) (
|
|||||||
|
|
||||||
// deleteImage deletes the named image from the registry, if supported.
|
// deleteImage deletes the named image from the registry, if supported.
|
||||||
func deleteImage(ctx *types.SystemContext, ref dockerReference) error {
|
func deleteImage(ctx *types.SystemContext, ref dockerReference) error {
|
||||||
c, err := newDockerClient(ctx, ref, true, "push")
|
c, err := newDockerClientFromRef(ctx, ref, true, "push")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
9
vendor/github.com/containers/image/image/docker_schema1.go
generated
vendored
9
vendor/github.com/containers/image/image/docker_schema1.go
generated
vendored
@ -161,14 +161,17 @@ func (m *manifestSchema1) imageInspectInfo() (*types.ImageInspectInfo, error) {
|
|||||||
if err := json.Unmarshal([]byte(m.History[0].V1Compatibility), v1); err != nil {
|
if err := json.Unmarshal([]byte(m.History[0].V1Compatibility), v1); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &types.ImageInspectInfo{
|
i := &types.ImageInspectInfo{
|
||||||
Tag: m.Tag,
|
Tag: m.Tag,
|
||||||
DockerVersion: v1.DockerVersion,
|
DockerVersion: v1.DockerVersion,
|
||||||
Created: v1.Created,
|
Created: v1.Created,
|
||||||
Labels: v1.Config.Labels,
|
|
||||||
Architecture: v1.Architecture,
|
Architecture: v1.Architecture,
|
||||||
Os: v1.OS,
|
Os: v1.OS,
|
||||||
}, nil
|
}
|
||||||
|
if v1.Config != nil {
|
||||||
|
i.Labels = v1.Config.Labels
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedImageNeedsLayerDiffIDs returns true iff UpdatedImage(options) needs InformationOnly.LayerDiffIDs.
|
// UpdatedImageNeedsLayerDiffIDs returns true iff UpdatedImage(options) needs InformationOnly.LayerDiffIDs.
|
||||||
|
9
vendor/github.com/containers/image/image/docker_schema2.go
generated
vendored
9
vendor/github.com/containers/image/image/docker_schema2.go
generated
vendored
@ -157,13 +157,16 @@ func (m *manifestSchema2) imageInspectInfo() (*types.ImageInspectInfo, error) {
|
|||||||
if err := json.Unmarshal(config, v1); err != nil {
|
if err := json.Unmarshal(config, v1); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &types.ImageInspectInfo{
|
i := &types.ImageInspectInfo{
|
||||||
DockerVersion: v1.DockerVersion,
|
DockerVersion: v1.DockerVersion,
|
||||||
Created: v1.Created,
|
Created: v1.Created,
|
||||||
Labels: v1.Config.Labels,
|
|
||||||
Architecture: v1.Architecture,
|
Architecture: v1.Architecture,
|
||||||
Os: v1.OS,
|
Os: v1.OS,
|
||||||
}, nil
|
}
|
||||||
|
if v1.Config != nil {
|
||||||
|
i.Labels = v1.Config.Labels
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedImageNeedsLayerDiffIDs returns true iff UpdatedImage(options) needs InformationOnly.LayerDiffIDs.
|
// UpdatedImageNeedsLayerDiffIDs returns true iff UpdatedImage(options) needs InformationOnly.LayerDiffIDs.
|
||||||
|
9
vendor/github.com/containers/image/image/oci.go
generated
vendored
9
vendor/github.com/containers/image/image/oci.go
generated
vendored
@ -130,13 +130,16 @@ func (m *manifestOCI1) imageInspectInfo() (*types.ImageInspectInfo, error) {
|
|||||||
if err := json.Unmarshal(config, v1); err != nil {
|
if err := json.Unmarshal(config, v1); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &types.ImageInspectInfo{
|
i := &types.ImageInspectInfo{
|
||||||
DockerVersion: v1.DockerVersion,
|
DockerVersion: v1.DockerVersion,
|
||||||
Created: v1.Created,
|
Created: v1.Created,
|
||||||
Labels: v1.Config.Labels,
|
|
||||||
Architecture: v1.Architecture,
|
Architecture: v1.Architecture,
|
||||||
Os: v1.OS,
|
Os: v1.OS,
|
||||||
}, nil
|
}
|
||||||
|
if v1.Config != nil {
|
||||||
|
i.Labels = v1.Config.Labels
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedImageNeedsLayerDiffIDs returns true iff UpdatedImage(options) needs InformationOnly.LayerDiffIDs.
|
// UpdatedImageNeedsLayerDiffIDs returns true iff UpdatedImage(options) needs InformationOnly.LayerDiffIDs.
|
||||||
|
1
vendor/github.com/containers/image/oci/archive/oci_dest.go
generated
vendored
1
vendor/github.com/containers/image/oci/archive/oci_dest.go
generated
vendored
@ -106,7 +106,6 @@ func (d *ociArchiveImageDestination) Commit() error {
|
|||||||
src := d.tempDirRef.tempDirectory
|
src := d.tempDirRef.tempDirectory
|
||||||
// path to save tarred up file
|
// path to save tarred up file
|
||||||
dst := d.ref.resolvedFile
|
dst := d.ref.resolvedFile
|
||||||
|
|
||||||
return tarDirectory(src, dst)
|
return tarDirectory(src, dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
295
vendor/github.com/containers/image/pkg/docker/config/config.go
generated
vendored
Normal file
295
vendor/github.com/containers/image/pkg/docker/config/config.go
generated
vendored
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/image/types"
|
||||||
|
helperclient "github.com/docker/docker-credential-helpers/client"
|
||||||
|
"github.com/docker/docker-credential-helpers/credentials"
|
||||||
|
"github.com/docker/docker/pkg/homedir"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dockerAuthConfig struct {
|
||||||
|
Auth string `json:"auth,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type dockerConfigFile struct {
|
||||||
|
AuthConfigs map[string]dockerAuthConfig `json:"auths"`
|
||||||
|
CredHelpers map[string]string `json:"credHelpers,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultPath = "/run/user"
|
||||||
|
authCfg = "containers"
|
||||||
|
authCfgFileName = "auth.json"
|
||||||
|
dockerCfg = ".docker"
|
||||||
|
dockerCfgFileName = "config.json"
|
||||||
|
dockerLegacyCfg = ".dockercfg"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrNotLoggedIn is returned for users not logged into a registry
|
||||||
|
// that they are trying to logout of
|
||||||
|
ErrNotLoggedIn = errors.New("not logged in")
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetAuthentication stores the username and password in the auth.json file
|
||||||
|
func SetAuthentication(ctx *types.SystemContext, registry, username, password string) error {
|
||||||
|
return modifyJSON(ctx, func(auths *dockerConfigFile) (bool, error) {
|
||||||
|
if ch, exists := auths.CredHelpers[registry]; exists {
|
||||||
|
return false, setAuthToCredHelper(ch, registry, username, password)
|
||||||
|
}
|
||||||
|
|
||||||
|
creds := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
||||||
|
newCreds := dockerAuthConfig{Auth: creds}
|
||||||
|
auths.AuthConfigs[registry] = newCreds
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAuthentication returns the registry credentials stored in
|
||||||
|
// either auth.json file or .docker/config.json
|
||||||
|
// If an entry is not found empty strings are returned for the username and password
|
||||||
|
func GetAuthentication(ctx *types.SystemContext, registry string) (string, string, error) {
|
||||||
|
if ctx != nil && ctx.DockerAuthConfig != nil {
|
||||||
|
return ctx.DockerAuthConfig.Username, ctx.DockerAuthConfig.Password, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerLegacyPath := filepath.Join(homedir.Get(), dockerLegacyCfg)
|
||||||
|
paths := [3]string{getPathToAuth(ctx), filepath.Join(homedir.Get(), dockerCfg, dockerCfgFileName), dockerLegacyPath}
|
||||||
|
|
||||||
|
for _, path := range paths {
|
||||||
|
legacyFormat := path == dockerLegacyPath
|
||||||
|
username, password, err := findAuthentication(registry, path, legacyFormat)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
if username != "" && password != "" {
|
||||||
|
return username, password, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserLoggedIn returns the username logged in to registry from either
|
||||||
|
// auth.json or XDG_RUNTIME_DIR
|
||||||
|
// Used to tell the user if someone is logged in to the registry when logging in
|
||||||
|
func GetUserLoggedIn(ctx *types.SystemContext, registry string) string {
|
||||||
|
path := getPathToAuth(ctx)
|
||||||
|
username, _, _ := findAuthentication(registry, path, false)
|
||||||
|
if username != "" {
|
||||||
|
return username
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAuthentication deletes the credentials stored in auth.json
|
||||||
|
func RemoveAuthentication(ctx *types.SystemContext, registry string) error {
|
||||||
|
return modifyJSON(ctx, func(auths *dockerConfigFile) (bool, error) {
|
||||||
|
// First try cred helpers.
|
||||||
|
if ch, exists := auths.CredHelpers[registry]; exists {
|
||||||
|
return false, deleteAuthFromCredHelper(ch, registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := auths.AuthConfigs[registry]; ok {
|
||||||
|
delete(auths.AuthConfigs, registry)
|
||||||
|
} else if _, ok := auths.AuthConfigs[normalizeRegistry(registry)]; ok {
|
||||||
|
delete(auths.AuthConfigs, normalizeRegistry(registry))
|
||||||
|
} else {
|
||||||
|
return false, ErrNotLoggedIn
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAllAuthentication deletes all the credentials stored in auth.json
|
||||||
|
func RemoveAllAuthentication(ctx *types.SystemContext) error {
|
||||||
|
return modifyJSON(ctx, func(auths *dockerConfigFile) (bool, error) {
|
||||||
|
auths.CredHelpers = make(map[string]string)
|
||||||
|
auths.AuthConfigs = make(map[string]dockerAuthConfig)
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPath gets the path of the auth.json file
|
||||||
|
// The path can be overriden by the user if the overwrite-path flag is set
|
||||||
|
// If the flag is not set and XDG_RUNTIME_DIR is ser, the auth.json file is saved in XDG_RUNTIME_DIR/containers
|
||||||
|
// Otherwise, the auth.json file is stored in /run/user/UID/containers
|
||||||
|
func getPathToAuth(ctx *types.SystemContext) string {
|
||||||
|
if ctx != nil {
|
||||||
|
if ctx.AuthFilePath != "" {
|
||||||
|
return ctx.AuthFilePath
|
||||||
|
}
|
||||||
|
if ctx.RootForImplicitAbsolutePaths != "" {
|
||||||
|
return filepath.Join(ctx.RootForImplicitAbsolutePaths, defaultPath, strconv.Itoa(os.Getuid()), authCfg, authCfgFileName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
|
||||||
|
if runtimeDir == "" {
|
||||||
|
runtimeDir = filepath.Join(defaultPath, strconv.Itoa(os.Getuid()))
|
||||||
|
}
|
||||||
|
return filepath.Join(runtimeDir, authCfg, authCfgFileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// readJSONFile unmarshals the authentications stored in the auth.json file and returns it
|
||||||
|
// or returns an empty dockerConfigFile data structure if auth.json does not exist
|
||||||
|
// if the file exists and is empty, readJSONFile returns an error
|
||||||
|
func readJSONFile(path string, legacyFormat bool) (dockerConfigFile, error) {
|
||||||
|
var auths dockerConfigFile
|
||||||
|
|
||||||
|
raw, err := ioutil.ReadFile(path)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
auths.AuthConfigs = map[string]dockerAuthConfig{}
|
||||||
|
return auths, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if legacyFormat {
|
||||||
|
if err = json.Unmarshal(raw, &auths.AuthConfigs); err != nil {
|
||||||
|
return dockerConfigFile{}, errors.Wrapf(err, "error unmarshaling JSON at %q", path)
|
||||||
|
}
|
||||||
|
return auths, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = json.Unmarshal(raw, &auths); err != nil {
|
||||||
|
return dockerConfigFile{}, errors.Wrapf(err, "error unmarshaling JSON at %q", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return auths, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// modifyJSON writes to auth.json if the dockerConfigFile has been updated
|
||||||
|
func modifyJSON(ctx *types.SystemContext, editor func(auths *dockerConfigFile) (bool, error)) error {
|
||||||
|
path := getPathToAuth(ctx)
|
||||||
|
dir := filepath.Dir(path)
|
||||||
|
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||||
|
if err = os.Mkdir(dir, 0700); err != nil {
|
||||||
|
return errors.Wrapf(err, "error creating directory %q", dir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auths, err := readJSONFile(path, false)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error reading JSON file %q", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
updated, err := editor(&auths)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error updating %q", path)
|
||||||
|
}
|
||||||
|
if updated {
|
||||||
|
newData, err := json.MarshalIndent(auths, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error marshaling JSON %q", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = ioutil.WriteFile(path, newData, 0755); err != nil {
|
||||||
|
return errors.Wrapf(err, "error writing to file %q", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAuthFromCredHelper(credHelper, registry string) (string, string, error) {
|
||||||
|
helperName := fmt.Sprintf("docker-credential-%s", credHelper)
|
||||||
|
p := helperclient.NewShellProgramFunc(helperName)
|
||||||
|
creds, err := helperclient.Get(p, registry)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
return creds.Username, creds.Secret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setAuthToCredHelper(credHelper, registry, username, password string) error {
|
||||||
|
helperName := fmt.Sprintf("docker-credential-%s", credHelper)
|
||||||
|
p := helperclient.NewShellProgramFunc(helperName)
|
||||||
|
creds := &credentials.Credentials{
|
||||||
|
ServerURL: registry,
|
||||||
|
Username: username,
|
||||||
|
Secret: password,
|
||||||
|
}
|
||||||
|
return helperclient.Store(p, creds)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteAuthFromCredHelper(credHelper, registry string) error {
|
||||||
|
helperName := fmt.Sprintf("docker-credential-%s", credHelper)
|
||||||
|
p := helperclient.NewShellProgramFunc(helperName)
|
||||||
|
return helperclient.Erase(p, registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
// findAuthentication looks for auth of registry in path
|
||||||
|
func findAuthentication(registry, path string, legacyFormat bool) (string, string, error) {
|
||||||
|
auths, err := readJSONFile(path, legacyFormat)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", errors.Wrapf(err, "error reading JSON file %q", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// First try cred helpers. They should always be normalized.
|
||||||
|
if ch, exists := auths.CredHelpers[registry]; exists {
|
||||||
|
return getAuthFromCredHelper(ch, registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
// I'm feeling lucky
|
||||||
|
if val, exists := auths.AuthConfigs[registry]; exists {
|
||||||
|
return decodeDockerAuth(val.Auth)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bad luck; let's normalize the entries first
|
||||||
|
registry = normalizeRegistry(registry)
|
||||||
|
normalizedAuths := map[string]dockerAuthConfig{}
|
||||||
|
for k, v := range auths.AuthConfigs {
|
||||||
|
normalizedAuths[normalizeRegistry(k)] = v
|
||||||
|
}
|
||||||
|
if val, exists := normalizedAuths[registry]; exists {
|
||||||
|
return decodeDockerAuth(val.Auth)
|
||||||
|
}
|
||||||
|
return "", "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeDockerAuth(s string) (string, string, error) {
|
||||||
|
decoded, err := base64.StdEncoding.DecodeString(s)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
parts := strings.SplitN(string(decoded), ":", 2)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
// if it's invalid just skip, as docker does
|
||||||
|
return "", "", nil
|
||||||
|
}
|
||||||
|
user := parts[0]
|
||||||
|
password := strings.Trim(parts[1], "\x00")
|
||||||
|
return user, password, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertToHostname converts a registry url which has http|https prepended
|
||||||
|
// to just an hostname.
|
||||||
|
// Copied from github.com/docker/docker/registry/auth.go
|
||||||
|
func convertToHostname(url string) string {
|
||||||
|
stripped := url
|
||||||
|
if strings.HasPrefix(url, "http://") {
|
||||||
|
stripped = strings.TrimPrefix(url, "http://")
|
||||||
|
} else if strings.HasPrefix(url, "https://") {
|
||||||
|
stripped = strings.TrimPrefix(url, "https://")
|
||||||
|
}
|
||||||
|
|
||||||
|
nameParts := strings.SplitN(stripped, "/", 2)
|
||||||
|
|
||||||
|
return nameParts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeRegistry(registry string) string {
|
||||||
|
normalized := convertToHostname(registry)
|
||||||
|
switch normalized {
|
||||||
|
case "registry-1.docker.io", "docker.io":
|
||||||
|
return "index.docker.io"
|
||||||
|
}
|
||||||
|
return normalized
|
||||||
|
}
|
2
vendor/github.com/containers/image/types/types.go
generated
vendored
2
vendor/github.com/containers/image/types/types.go
generated
vendored
@ -304,6 +304,8 @@ type SystemContext struct {
|
|||||||
RegistriesDirPath string
|
RegistriesDirPath string
|
||||||
// Path to the system-wide registries configuration file
|
// Path to the system-wide registries configuration file
|
||||||
SystemRegistriesConfPath string
|
SystemRegistriesConfPath string
|
||||||
|
// If not "", overrides the default path for the authentication file
|
||||||
|
AuthFilePath string
|
||||||
|
|
||||||
// === OCI.Transport overrides ===
|
// === OCI.Transport overrides ===
|
||||||
// If not "", a directory containing a CA certificate (ending with ".crt"),
|
// If not "", a directory containing a CA certificate (ending with ".crt"),
|
||||||
|
97
vendor/github.com/containers/storage/pkg/archive/example_changes.go
generated
vendored
97
vendor/github.com/containers/storage/pkg/archive/example_changes.go
generated
vendored
@ -1,97 +0,0 @@
|
|||||||
// +build ignore
|
|
||||||
|
|
||||||
// Simple tool to create an archive stream from an old and new directory
|
|
||||||
//
|
|
||||||
// By default it will stream the comparison of two temporary directories with junk files
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
|
|
||||||
"github.com/containers/storage/pkg/archive"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
flDebug = flag.Bool("D", false, "debugging output")
|
|
||||||
flNewDir = flag.String("newdir", "", "")
|
|
||||||
flOldDir = flag.String("olddir", "", "")
|
|
||||||
log = logrus.New()
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Usage = func() {
|
|
||||||
fmt.Println("Produce a tar from comparing two directory paths. By default a demo tar is created of around 200 files (including hardlinks)")
|
|
||||||
fmt.Printf("%s [OPTIONS]\n", os.Args[0])
|
|
||||||
flag.PrintDefaults()
|
|
||||||
}
|
|
||||||
flag.Parse()
|
|
||||||
log.Out = os.Stderr
|
|
||||||
if (len(os.Getenv("DEBUG")) > 0) || *flDebug {
|
|
||||||
logrus.SetLevel(logrus.DebugLevel)
|
|
||||||
}
|
|
||||||
var newDir, oldDir string
|
|
||||||
|
|
||||||
if len(*flNewDir) == 0 {
|
|
||||||
var err error
|
|
||||||
newDir, err = ioutil.TempDir("", "storage-test-newDir")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(newDir)
|
|
||||||
if _, err := prepareUntarSourceDirectory(100, newDir, true); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newDir = *flNewDir
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(*flOldDir) == 0 {
|
|
||||||
oldDir, err := ioutil.TempDir("", "storage-test-oldDir")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(oldDir)
|
|
||||||
} else {
|
|
||||||
oldDir = *flOldDir
|
|
||||||
}
|
|
||||||
|
|
||||||
changes, err := archive.ChangesDirs(newDir, oldDir)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
a, err := archive.ExportChanges(newDir, changes)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer a.Close()
|
|
||||||
|
|
||||||
i, err := io.Copy(os.Stdout, a)
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "wrote archive of %d bytes", i)
|
|
||||||
}
|
|
||||||
|
|
||||||
func prepareUntarSourceDirectory(numberOfFiles int, targetPath string, makeLinks bool) (int, error) {
|
|
||||||
fileData := []byte("fooo")
|
|
||||||
for n := 0; n < numberOfFiles; n++ {
|
|
||||||
fileName := fmt.Sprintf("file-%d", n)
|
|
||||||
if err := ioutil.WriteFile(path.Join(targetPath, fileName), fileData, 0700); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if makeLinks {
|
|
||||||
if err := os.Link(path.Join(targetPath, fileName), path.Join(targetPath, fileName+"-link")); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
totalSize := numberOfFiles * len(fileData)
|
|
||||||
return totalSize, nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user