mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Updated deps
This commit is contained in:
@@ -3,6 +3,8 @@ package datastoreutil
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
"gitlab-odx.oracle.com/odx/functions/api/models"
|
"gitlab-odx.oracle.com/odx/functions/api/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -135,3 +137,12 @@ func (v *validator) GetTask(ctx context.Context, callID string) (*models.FnCall,
|
|||||||
}
|
}
|
||||||
return v.Datastore.GetTask(ctx, callID)
|
return v.Datastore.GetTask(ctx, callID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *validator) DeleteLog(ctx context.Context, callID string) error {
|
||||||
|
return v.Datastore.DeleteLog(ctx, callID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDatabase returns the underlying sqlx database implementation
|
||||||
|
func (v *validator) GetDatabase() *sqlx.DB {
|
||||||
|
return v.Datastore.GetDatabase()
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package datastore
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
"gitlab-odx.oracle.com/odx/functions/api/datastore/internal/datastoreutil"
|
"gitlab-odx.oracle.com/odx/functions/api/datastore/internal/datastoreutil"
|
||||||
"gitlab-odx.oracle.com/odx/functions/api/logs"
|
"gitlab-odx.oracle.com/odx/functions/api/logs"
|
||||||
"gitlab-odx.oracle.com/odx/functions/api/models"
|
"gitlab-odx.oracle.com/odx/functions/api/models"
|
||||||
@@ -167,3 +169,8 @@ func (m *mock) GetTask(ctx context.Context, callID string) (*models.FnCall, erro
|
|||||||
func (m *mock) GetTasks(ctx context.Context, filter *models.CallFilter) (models.FnCalls, error) {
|
func (m *mock) GetTasks(ctx context.Context, filter *models.CallFilter) (models.FnCalls, error) {
|
||||||
return m.Calls, nil
|
return m.Calls, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDatabase returns nil here since shouldn't really be used
|
||||||
|
func (m *mock) GetDatabase() *sqlx.DB {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -757,3 +757,8 @@ func scanCall(scanner RowScanner, call *models.FnCall) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDatabase returns the underlying sqlx database implementation
|
||||||
|
func (ds *sqlStore) GetDatabase() *sqlx.DB {
|
||||||
|
return ds.db
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package models
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Datastore interface {
|
type Datastore interface {
|
||||||
@@ -64,6 +66,9 @@ type Datastore interface {
|
|||||||
|
|
||||||
// Implement FnLog methods for convenience
|
// Implement FnLog methods for convenience
|
||||||
FnLog
|
FnLog
|
||||||
|
|
||||||
|
// GetDatabase returns the underlying sqlx database implementation
|
||||||
|
GetDatabase() *sqlx.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
2
glide.lock
generated
2
glide.lock
generated
@@ -40,7 +40,7 @@ imports:
|
|||||||
subpackages:
|
subpackages:
|
||||||
- cli/config/configfile
|
- cli/config/configfile
|
||||||
- name: github.com/docker/distribution
|
- name: github.com/docker/distribution
|
||||||
version: a25b9ef0c9fe242ac04bb20d3a028442b7d266b6
|
version: f86db6b22663a27ba4d278220b7e34be528b1e79
|
||||||
subpackages:
|
subpackages:
|
||||||
- context
|
- context
|
||||||
- digest
|
- digest
|
||||||
|
|||||||
@@ -28,9 +28,7 @@ import:
|
|||||||
subpackages:
|
subpackages:
|
||||||
- cli/config/configfile
|
- cli/config/configfile
|
||||||
- package: github.com/docker/distribution
|
- package: github.com/docker/distribution
|
||||||
version: ^2.6.1
|
branch: master
|
||||||
subpackages:
|
|
||||||
- manifest/schema1
|
|
||||||
- package: github.com/fsouza/go-dockerclient
|
- package: github.com/fsouza/go-dockerclient
|
||||||
- package: github.com/garyburd/redigo
|
- package: github.com/garyburd/redigo
|
||||||
subpackages:
|
subpackages:
|
||||||
|
|||||||
8
vendor/github.com/docker/distribution/BUILDING.md
generated
vendored
8
vendor/github.com/docker/distribution/BUILDING.md
generated
vendored
@@ -71,9 +71,7 @@ commands, such as `go test`, should work per package (please see
|
|||||||
A `Makefile` has been provided as a convenience to support repeatable builds.
|
A `Makefile` has been provided as a convenience to support repeatable builds.
|
||||||
Please install the following into `GOPATH` for it to work:
|
Please install the following into `GOPATH` for it to work:
|
||||||
|
|
||||||
go get github.com/tools/godep github.com/golang/lint/golint
|
go get github.com/golang/lint/golint
|
||||||
|
|
||||||
**TODO(stevvooe):** Add a `make setup` command to Makefile to run this. Have to think about how to interact with Godeps properly.
|
|
||||||
|
|
||||||
Once these commands are available in the `GOPATH`, run `make` to get a full
|
Once these commands are available in the `GOPATH`, run `make` to get a full
|
||||||
build:
|
build:
|
||||||
@@ -105,8 +103,8 @@ build:
|
|||||||
+ /Users/sday/go/src/github.com/docker/distribution/bin/registry-api-descriptor-template
|
+ /Users/sday/go/src/github.com/docker/distribution/bin/registry-api-descriptor-template
|
||||||
+ binaries
|
+ binaries
|
||||||
|
|
||||||
The above provides a repeatable build using the contents of the vendored
|
The above provides a repeatable build using the contents of the vendor
|
||||||
Godeps directory. This includes formatting, vetting, linting, building,
|
directory. This includes formatting, vetting, linting, building,
|
||||||
testing and generating tagged binaries. We can verify this worked by running
|
testing and generating tagged binaries. We can verify this worked by running
|
||||||
the registry binary generated in the "./bin" directory:
|
the registry binary generated in the "./bin" directory:
|
||||||
|
|
||||||
|
|||||||
6
vendor/github.com/docker/distribution/CHANGELOG.md
generated
vendored
6
vendor/github.com/docker/distribution/CHANGELOG.md
generated
vendored
@@ -1,11 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 2.6.1 (2017-04-05)
|
|
||||||
|
|
||||||
#### Registry
|
|
||||||
- Fix `Forwarded` header handling, revert use of `X-Forwarded-Port`
|
|
||||||
- Use driver `Stat` for registry health check
|
|
||||||
|
|
||||||
## 2.6.0 (2017-01-18)
|
## 2.6.0 (2017-01-18)
|
||||||
|
|
||||||
#### Storage
|
#### Storage
|
||||||
|
|||||||
5
vendor/github.com/docker/distribution/Dockerfile
generated
vendored
5
vendor/github.com/docker/distribution/Dockerfile
generated
vendored
@@ -1,8 +1,11 @@
|
|||||||
FROM golang:1.7-alpine
|
FROM golang:1.8-alpine
|
||||||
|
|
||||||
ENV DISTRIBUTION_DIR /go/src/github.com/docker/distribution
|
ENV DISTRIBUTION_DIR /go/src/github.com/docker/distribution
|
||||||
ENV DOCKER_BUILDTAGS include_oss include_gcs
|
ENV DOCKER_BUILDTAGS include_oss include_gcs
|
||||||
|
|
||||||
|
ARG GOOS=linux
|
||||||
|
ARG GOARCH=amd64
|
||||||
|
|
||||||
RUN set -ex \
|
RUN set -ex \
|
||||||
&& apk add --no-cache make git
|
&& apk add --no-cache make git
|
||||||
|
|
||||||
|
|||||||
458
vendor/github.com/docker/distribution/Godeps/Godeps.json
generated
vendored
458
vendor/github.com/docker/distribution/Godeps/Godeps.json
generated
vendored
@@ -1,458 +0,0 @@
|
|||||||
{
|
|
||||||
"ImportPath": "github.com/docker/distribution",
|
|
||||||
"GoVersion": "go1.6",
|
|
||||||
"GodepVersion": "v74",
|
|
||||||
"Packages": [
|
|
||||||
"./..."
|
|
||||||
],
|
|
||||||
"Deps": [
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/Azure/azure-sdk-for-go/storage",
|
|
||||||
"Comment": "v5.0.0-beta-6-g0b5fe2a",
|
|
||||||
"Rev": "0b5fe2abe0271ba07049eacaa65922d67c319543"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/Sirupsen/logrus",
|
|
||||||
"Comment": "v0.7.3",
|
|
||||||
"Rev": "55eb11d21d2a31a3cc93838241d04800f52e823d"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/Sirupsen/logrus/formatters/logstash",
|
|
||||||
"Comment": "v0.7.3",
|
|
||||||
"Rev": "55eb11d21d2a31a3cc93838241d04800f52e823d"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/aws",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/awserr",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/awsutil",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/client",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/client/metadata",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/corehandlers",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/credentials",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/defaults",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/ec2metadata",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/request",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/session",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/signer/v4",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/private/endpoints",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/query",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/query/queryutil",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/rest",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/restxml",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/private/waiter",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/service/cloudfront/sign",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/service/s3",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/vendor/github.com/go-ini/ini",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/aws/aws-sdk-go/vendor/github.com/jmespath/go-jmespath",
|
|
||||||
"Comment": "v1.2.4",
|
|
||||||
"Rev": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/bugsnag/bugsnag-go",
|
|
||||||
"Comment": "v1.0.2-5-gb1d1530",
|
|
||||||
"Rev": "b1d153021fcd90ca3f080db36bec96dc690fb274"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/bugsnag/bugsnag-go/errors",
|
|
||||||
"Comment": "v1.0.2-5-gb1d1530",
|
|
||||||
"Rev": "b1d153021fcd90ca3f080db36bec96dc690fb274"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/bugsnag/osext",
|
|
||||||
"Rev": "0dd3f918b21bec95ace9dc86c7e70266cfc5c702"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/bugsnag/panicwrap",
|
|
||||||
"Comment": "1.0.0-2-ge2c2850",
|
|
||||||
"Rev": "e2c28503fcd0675329da73bf48b33404db873782"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/denverdino/aliyungo/common",
|
|
||||||
"Rev": "afedced274aa9a7fcdd47ac97018f0f8db4e5de2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/denverdino/aliyungo/oss",
|
|
||||||
"Rev": "afedced274aa9a7fcdd47ac97018f0f8db4e5de2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/denverdino/aliyungo/util",
|
|
||||||
"Rev": "afedced274aa9a7fcdd47ac97018f0f8db4e5de2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/docker/goamz/aws",
|
|
||||||
"Rev": "f0a21f5b2e12f83a505ecf79b633bb2035cf6f85"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/docker/goamz/s3",
|
|
||||||
"Rev": "f0a21f5b2e12f83a505ecf79b633bb2035cf6f85"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/docker/libtrust",
|
|
||||||
"Rev": "fa567046d9b14f6aa788882a950d69651d230b21"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/garyburd/redigo/internal",
|
|
||||||
"Rev": "535138d7bcd717d6531c701ef5933d98b1866257"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/garyburd/redigo/redis",
|
|
||||||
"Rev": "535138d7bcd717d6531c701ef5933d98b1866257"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/golang/protobuf/proto",
|
|
||||||
"Rev": "8d92cf5fc15a4382f8964b08e1f42a75c0591aa3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/gorilla/context",
|
|
||||||
"Rev": "14f550f51af52180c2eefed15e5fd18d63c0a64a"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/gorilla/handlers",
|
|
||||||
"Rev": "60c7bfde3e33c201519a200a4507a158cc03a17b"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/gorilla/mux",
|
|
||||||
"Rev": "e444e69cbd2e2e3e0749a2f3c717cec491552bbf"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/inconshreveable/mousetrap",
|
|
||||||
"Rev": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/mitchellh/mapstructure",
|
|
||||||
"Rev": "482a9fd5fa83e8c4e7817413b80f3eb8feec03ef"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/ncw/swift",
|
|
||||||
"Rev": "ce444d6d47c51d4dda9202cd38f5094dd8e27e86"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/ncw/swift/swifttest",
|
|
||||||
"Rev": "ce444d6d47c51d4dda9202cd38f5094dd8e27e86"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/spf13/cobra",
|
|
||||||
"Rev": "312092086bed4968099259622145a0c9ae280064"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/spf13/pflag",
|
|
||||||
"Rev": "5644820622454e71517561946e3d94b9f9db6842"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/stevvooe/resumable",
|
|
||||||
"Rev": "51ad44105773cafcbe91927f70ac68e1bf78f8b4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/stevvooe/resumable/sha256",
|
|
||||||
"Rev": "51ad44105773cafcbe91927f70ac68e1bf78f8b4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/stevvooe/resumable/sha512",
|
|
||||||
"Rev": "51ad44105773cafcbe91927f70ac68e1bf78f8b4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/yvasiyarov/go-metrics",
|
|
||||||
"Rev": "57bccd1ccd43f94bb17fdd8bf3007059b802f85e"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/yvasiyarov/gorelic",
|
|
||||||
"Comment": "v0.0.6-8-ga9bba5b",
|
|
||||||
"Rev": "a9bba5b9ab508a086f9a12b8c51fab68478e2128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/yvasiyarov/newrelic_platform_go",
|
|
||||||
"Rev": "b21fdbd4370f3717f3bbd2bf41c223bc273068e6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/crypto/bcrypt",
|
|
||||||
"Rev": "c10c31b5e94b6f7a0283272dc2bb27163dcea24b"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/crypto/blowfish",
|
|
||||||
"Rev": "c10c31b5e94b6f7a0283272dc2bb27163dcea24b"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/crypto/ocsp",
|
|
||||||
"Rev": "c10c31b5e94b6f7a0283272dc2bb27163dcea24b"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/net/context",
|
|
||||||
"Rev": "4876518f9e71663000c348837735820161a42df7"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/net/context/ctxhttp",
|
|
||||||
"Rev": "4876518f9e71663000c348837735820161a42df7"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/net/http2",
|
|
||||||
"Rev": "4876518f9e71663000c348837735820161a42df7"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/net/http2/hpack",
|
|
||||||
"Rev": "4876518f9e71663000c348837735820161a42df7"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/net/internal/timeseries",
|
|
||||||
"Rev": "4876518f9e71663000c348837735820161a42df7"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/net/trace",
|
|
||||||
"Rev": "4876518f9e71663000c348837735820161a42df7"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/oauth2",
|
|
||||||
"Rev": "045497edb6234273d67dbc25da3f2ddbc4c4cacf"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/oauth2/google",
|
|
||||||
"Rev": "045497edb6234273d67dbc25da3f2ddbc4c4cacf"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/oauth2/internal",
|
|
||||||
"Rev": "045497edb6234273d67dbc25da3f2ddbc4c4cacf"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/oauth2/jws",
|
|
||||||
"Rev": "045497edb6234273d67dbc25da3f2ddbc4c4cacf"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/oauth2/jwt",
|
|
||||||
"Rev": "045497edb6234273d67dbc25da3f2ddbc4c4cacf"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/time/rate",
|
|
||||||
"Rev": "a4bde12657593d5e90d0533a3e4fd95e635124cb"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/api/gensupport",
|
|
||||||
"Rev": "9bf6e6e569ff057f75d9604a46c52928f17d2b54"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/api/googleapi",
|
|
||||||
"Rev": "9bf6e6e569ff057f75d9604a46c52928f17d2b54"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/api/googleapi/internal/uritemplates",
|
|
||||||
"Rev": "9bf6e6e569ff057f75d9604a46c52928f17d2b54"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/api/storage/v1",
|
|
||||||
"Rev": "9bf6e6e569ff057f75d9604a46c52928f17d2b54"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/appengine",
|
|
||||||
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/appengine/internal",
|
|
||||||
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/appengine/internal/app_identity",
|
|
||||||
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/appengine/internal/base",
|
|
||||||
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/appengine/internal/datastore",
|
|
||||||
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/appengine/internal/log",
|
|
||||||
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/appengine/internal/modules",
|
|
||||||
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/appengine/internal/remote_api",
|
|
||||||
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/cloud",
|
|
||||||
"Rev": "975617b05ea8a58727e6c1a06b6161ff4185a9f2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/cloud/compute/metadata",
|
|
||||||
"Rev": "975617b05ea8a58727e6c1a06b6161ff4185a9f2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/cloud/internal",
|
|
||||||
"Rev": "975617b05ea8a58727e6c1a06b6161ff4185a9f2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/cloud/internal/opts",
|
|
||||||
"Rev": "975617b05ea8a58727e6c1a06b6161ff4185a9f2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/cloud/storage",
|
|
||||||
"Rev": "975617b05ea8a58727e6c1a06b6161ff4185a9f2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/grpc",
|
|
||||||
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/grpc/codes",
|
|
||||||
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/grpc/credentials",
|
|
||||||
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/grpc/grpclog",
|
|
||||||
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/grpc/internal",
|
|
||||||
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/grpc/metadata",
|
|
||||||
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/grpc/naming",
|
|
||||||
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/grpc/peer",
|
|
||||||
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "google.golang.org/grpc/transport",
|
|
||||||
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "gopkg.in/check.v1",
|
|
||||||
"Rev": "64131543e7896d5bcc6bd5a76287eb75ea96c673"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "gopkg.in/yaml.v2",
|
|
||||||
"Rev": "bef53efd0c76e49e6de55ead051f886bea7e9420"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "rsc.io/letsencrypt",
|
|
||||||
"Rev": "a019c9e6fce0c7132679dea13bd8df7c86ffe26c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "rsc.io/letsencrypt/vendor/github.com/xenolf/lego/acme",
|
|
||||||
"Rev": "a019c9e6fce0c7132679dea13bd8df7c86ffe26c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "rsc.io/letsencrypt/vendor/gopkg.in/square/go-jose.v1",
|
|
||||||
"Rev": "a019c9e6fce0c7132679dea13bd8df7c86ffe26c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "rsc.io/letsencrypt/vendor/gopkg.in/square/go-jose.v1/cipher",
|
|
||||||
"Rev": "a019c9e6fce0c7132679dea13bd8df7c86ffe26c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "rsc.io/letsencrypt/vendor/gopkg.in/square/go-jose.v1/json",
|
|
||||||
"Rev": "a019c9e6fce0c7132679dea13bd8df7c86ffe26c"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
5
vendor/github.com/docker/distribution/Godeps/Readme
generated
vendored
5
vendor/github.com/docker/distribution/Godeps/Readme
generated
vendored
@@ -1,5 +0,0 @@
|
|||||||
This directory tree is generated automatically by godep.
|
|
||||||
|
|
||||||
Please do not edit.
|
|
||||||
|
|
||||||
See https://github.com/tools/godep for more information.
|
|
||||||
26
vendor/github.com/docker/distribution/Makefile
generated
vendored
26
vendor/github.com/docker/distribution/Makefile
generated
vendored
@@ -35,7 +35,7 @@ PKGS=$(shell go list -tags "${DOCKER_BUILDTAGS}" ./... | grep -v ^github.com/doc
|
|||||||
|
|
||||||
# Resolving binary dependencies for specific targets
|
# Resolving binary dependencies for specific targets
|
||||||
GOLINT=$(shell which golint || echo '')
|
GOLINT=$(shell which golint || echo '')
|
||||||
GODEP=$(shell which godep || echo '')
|
VNDR=$(shell which vndr || echo '')
|
||||||
|
|
||||||
${PREFIX}/bin/registry: $(GOFILES)
|
${PREFIX}/bin/registry: $(GOFILES)
|
||||||
@echo "+ $@"
|
@echo "+ $@"
|
||||||
@@ -86,24 +86,14 @@ clean:
|
|||||||
@echo "+ $@"
|
@echo "+ $@"
|
||||||
@rm -rf "${PREFIX}/bin/registry" "${PREFIX}/bin/digest" "${PREFIX}/bin/registry-api-descriptor-template"
|
@rm -rf "${PREFIX}/bin/registry" "${PREFIX}/bin/digest" "${PREFIX}/bin/registry-api-descriptor-template"
|
||||||
|
|
||||||
dep-save:
|
dep-validate:
|
||||||
@echo "+ $@"
|
|
||||||
$(if $(GODEP), , \
|
|
||||||
$(error Please install godep: go get github.com/tools/godep))
|
|
||||||
@$(GODEP) save $(PKGS)
|
|
||||||
|
|
||||||
dep-restore:
|
|
||||||
@echo "+ $@"
|
|
||||||
$(if $(GODEP), , \
|
|
||||||
$(error Please install godep: go get github.com/tools/godep))
|
|
||||||
@$(GODEP) restore -v
|
|
||||||
|
|
||||||
dep-validate: dep-restore
|
|
||||||
@echo "+ $@"
|
@echo "+ $@"
|
||||||
|
$(if $(VNDR), , \
|
||||||
|
$(error Please install vndr: go get github.com/lk4d4/vndr))
|
||||||
@rm -Rf .vendor.bak
|
@rm -Rf .vendor.bak
|
||||||
@mv vendor .vendor.bak
|
@mv vendor .vendor.bak
|
||||||
@rm -Rf Godeps
|
@$(VNDR)
|
||||||
@$(GODEP) save ./...
|
|
||||||
@test -z "$$(diff -r vendor .vendor.bak 2>&1 | tee /dev/stderr)" || \
|
@test -z "$$(diff -r vendor .vendor.bak 2>&1 | tee /dev/stderr)" || \
|
||||||
(echo >&2 "+ borked dependencies! what you have in Godeps/Godeps.json does not match with what you have in vendor" && false)
|
(echo >&2 "+ inconsistent dependencies! what you have in vendor.conf does not match with what you have in vendor" && false)
|
||||||
@rm -Rf .vendor.bak
|
@rm -Rf vendor
|
||||||
|
@mv .vendor.bak vendor
|
||||||
|
|||||||
3
vendor/github.com/docker/distribution/README.md
generated
vendored
3
vendor/github.com/docker/distribution/README.md
generated
vendored
@@ -76,8 +76,7 @@ may be the better choice.
|
|||||||
For those who have previously deployed their own registry based on the Registry
|
For those who have previously deployed their own registry based on the Registry
|
||||||
1.0 implementation and wish to deploy a Registry 2.0 while retaining images,
|
1.0 implementation and wish to deploy a Registry 2.0 while retaining images,
|
||||||
data migration is required. A tool to assist with migration efforts has been
|
data migration is required. A tool to assist with migration efforts has been
|
||||||
created. For more information see [docker/migrator]
|
created. For more information see [docker/migrator](https://github.com/docker/migrator).
|
||||||
(https://github.com/docker/migrator).
|
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
|
|||||||
14
vendor/github.com/docker/distribution/RELEASE-CHECKLIST.md
generated
vendored
14
vendor/github.com/docker/distribution/RELEASE-CHECKLIST.md
generated
vendored
@@ -1,6 +1,10 @@
|
|||||||
## Registry Release Checklist
|
## Registry Release Checklist
|
||||||
|
|
||||||
10. Compile release notes detailing features and since the last release. Update the `CHANGELOG.md` file.
|
10. Compile release notes detailing features and since the last release.
|
||||||
|
|
||||||
|
Update the `CHANGELOG.md` file and create a PR to master with the updates.
|
||||||
|
Once that PR has been approved by maintainers the change may be cherry-picked
|
||||||
|
to the release branch (new release branches may be forked from this commit).
|
||||||
|
|
||||||
20. Update the version file: `https://github.com/docker/distribution/blob/master/version/version.go`
|
20. Update the version file: `https://github.com/docker/distribution/blob/master/version/version.go`
|
||||||
|
|
||||||
@@ -12,8 +16,12 @@ make AUTHORS
|
|||||||
|
|
||||||
40. Create a signed tag.
|
40. Create a signed tag.
|
||||||
|
|
||||||
Distribution uses semantic versioning. Tags are of the format `vx.y.z[-rcn]`
|
Distribution uses semantic versioning. Tags are of the format
|
||||||
You will need PGP installed and a PGP key which has been added to your Github account. The comment for the tag should include the release notes.
|
`vx.y.z[-rcn]`. You will need PGP installed and a PGP key which has been added
|
||||||
|
to your Github account. The comment for the tag should include the release
|
||||||
|
notes, use previous tags as a guide for formatting consistently. Run
|
||||||
|
`git tag -s vx.y.z[-rcn]` to create tag and `git -v vx.y.z[-rcn]` to verify tag,
|
||||||
|
check comment and correct commit hash.
|
||||||
|
|
||||||
50. Push the signed tag
|
50. Push the signed tag
|
||||||
|
|
||||||
|
|||||||
4
vendor/github.com/docker/distribution/blobs.go
generated
vendored
4
vendor/github.com/docker/distribution/blobs.go
generated
vendored
@@ -8,8 +8,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -152,7 +152,7 @@ type BlobProvider interface {
|
|||||||
|
|
||||||
// BlobServer can serve blobs via http.
|
// BlobServer can serve blobs via http.
|
||||||
type BlobServer interface {
|
type BlobServer interface {
|
||||||
// ServeBlob attempts to serve the blob, identifed by dgst, via http. The
|
// ServeBlob attempts to serve the blob, identified by dgst, via http. The
|
||||||
// service may decide to redirect the client elsewhere or serve the data
|
// service may decide to redirect the client elsewhere or serve the data
|
||||||
// directly.
|
// directly.
|
||||||
//
|
//
|
||||||
|
|||||||
17
vendor/github.com/docker/distribution/circle.yml
generated
vendored
17
vendor/github.com/docker/distribution/circle.yml
generated
vendored
@@ -8,7 +8,7 @@ machine:
|
|||||||
|
|
||||||
post:
|
post:
|
||||||
# go
|
# go
|
||||||
- gvm install go1.7 --prefer-binary --name=stable
|
- gvm install go1.8 --prefer-binary --name=stable
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
# Convenient shortcuts to "common" locations
|
# Convenient shortcuts to "common" locations
|
||||||
@@ -34,7 +34,7 @@ dependencies:
|
|||||||
|
|
||||||
override:
|
override:
|
||||||
# Install dependencies for every copied clone/go version
|
# Install dependencies for every copied clone/go version
|
||||||
- gvm use stable && go get github.com/tools/godep:
|
- gvm use stable && go get github.com/lk4d4/vndr:
|
||||||
pwd: $BASE_STABLE
|
pwd: $BASE_STABLE
|
||||||
|
|
||||||
post:
|
post:
|
||||||
@@ -49,14 +49,15 @@ test:
|
|||||||
# - gvm use old && go version
|
# - gvm use old && go version
|
||||||
- gvm use stable && go version
|
- gvm use stable && go version
|
||||||
|
|
||||||
# todo(richard): replace with a more robust vendoring solution. Removed due to a fundamental disagreement in godep philosophies.
|
|
||||||
# Ensure validation of dependencies
|
# Ensure validation of dependencies
|
||||||
# - gvm use stable && if test -n "`git diff --stat=1000 master | grep -Ei \"vendor|godeps\"`"; then make dep-validate; fi:
|
- git fetch origin:
|
||||||
# pwd: $BASE_STABLE
|
pwd: $BASE_STABLE
|
||||||
|
- gvm use stable && if test -n "`git diff --stat=1000 origin/master | grep -E \"^[[:space:]]*vendor\"`"; then make dep-validate; fi:
|
||||||
|
pwd: $BASE_STABLE
|
||||||
|
|
||||||
# First thing: build everything. This will catch compile errors, and it's
|
# First thing: build everything. This will catch compile errors, and it's
|
||||||
# also necessary for go vet to work properly (see #807).
|
# also necessary for go vet to work properly (see #807).
|
||||||
- gvm use stable && godep go install $(go list ./... | grep -v "/vendor/"):
|
- gvm use stable && go install $(go list ./... | grep -v "/vendor/"):
|
||||||
pwd: $BASE_STABLE
|
pwd: $BASE_STABLE
|
||||||
|
|
||||||
# FMT
|
# FMT
|
||||||
@@ -73,12 +74,12 @@ test:
|
|||||||
|
|
||||||
override:
|
override:
|
||||||
# Test stable, and report
|
# Test stable, and report
|
||||||
- gvm use stable; export ROOT_PACKAGE=$(go list .); go list -tags "$DOCKER_BUILDTAGS" ./... | grep -v "/vendor/" | xargs -L 1 -I{} bash -c 'export PACKAGE={}; godep go test -tags "$DOCKER_BUILDTAGS" -test.short -coverprofile=$GOPATH/src/$PACKAGE/coverage.out -coverpkg=$(./coverpkg.sh $PACKAGE $ROOT_PACKAGE) $PACKAGE':
|
- gvm use stable; export ROOT_PACKAGE=$(go list .); go list -tags "$DOCKER_BUILDTAGS" ./... | grep -v "/vendor/" | xargs -L 1 -I{} bash -c 'export PACKAGE={}; go test -tags "$DOCKER_BUILDTAGS" -test.short -coverprofile=$GOPATH/src/$PACKAGE/coverage.out -coverpkg=$(./coverpkg.sh $PACKAGE $ROOT_PACKAGE) $PACKAGE':
|
||||||
timeout: 1000
|
timeout: 1000
|
||||||
pwd: $BASE_STABLE
|
pwd: $BASE_STABLE
|
||||||
|
|
||||||
# Test stable with race
|
# Test stable with race
|
||||||
- gvm use stable; export ROOT_PACKAGE=$(go list .); go list -tags "$DOCKER_BUILDTAGS" ./... | grep -v "/vendor/" | grep -v "registry/handlers" | grep -v "registry/storage/driver" | xargs -L 1 -I{} bash -c 'export PACKAGE={}; godep go test -race -tags "$DOCKER_BUILDTAGS" -test.short $PACKAGE':
|
- gvm use stable; export ROOT_PACKAGE=$(go list .); go list -tags "$DOCKER_BUILDTAGS" ./... | grep -v "/vendor/" | grep -v "registry/handlers" | grep -v "registry/storage/driver" | xargs -L 1 -I{} bash -c 'export PACKAGE={}; go test -race -tags "$DOCKER_BUILDTAGS" -test.short $PACKAGE':
|
||||||
timeout: 1000
|
timeout: 1000
|
||||||
pwd: $BASE_STABLE
|
pwd: $BASE_STABLE
|
||||||
post:
|
post:
|
||||||
|
|||||||
4
vendor/github.com/docker/distribution/cmd/digest/main.go
generated
vendored
4
vendor/github.com/docker/distribution/cmd/digest/main.go
generated
vendored
@@ -7,8 +7,8 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/version"
|
"github.com/docker/distribution/version"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -32,7 +32,7 @@ func init() {
|
|||||||
|
|
||||||
func usage() {
|
func usage() {
|
||||||
fmt.Fprintf(os.Stderr, "usage: %s [files...]\n", os.Args[0])
|
fmt.Fprintf(os.Stderr, "usage: %s [files...]\n", os.Args[0])
|
||||||
fmt.Fprintf(os.Stderr, `
|
fmt.Fprint(os.Stderr, `
|
||||||
Calculate the digest of one or more input files, emitting the result
|
Calculate the digest of one or more input files, emitting the result
|
||||||
to standard out. If no files are provided, the digest of stdin will
|
to standard out. If no files are provided, the digest of stdin will
|
||||||
be calculated.
|
be calculated.
|
||||||
|
|||||||
14
vendor/github.com/docker/distribution/configuration/configuration.go
generated
vendored
14
vendor/github.com/docker/distribution/configuration/configuration.go
generated
vendored
@@ -1,6 +1,7 @@
|
|||||||
package configuration
|
package configuration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -132,7 +133,7 @@ type Configuration struct {
|
|||||||
|
|
||||||
// HTTP2 configuration options
|
// HTTP2 configuration options
|
||||||
HTTP2 struct {
|
HTTP2 struct {
|
||||||
// Specifies wether the registry should disallow clients attempting
|
// Specifies whether the registry should disallow clients attempting
|
||||||
// to connect via http2. If set to true, only http/1.1 is supported.
|
// to connect via http2. If set to true, only http/1.1 is supported.
|
||||||
Disabled bool `yaml:"disabled,omitempty"`
|
Disabled bool `yaml:"disabled,omitempty"`
|
||||||
} `yaml:"http2,omitempty"`
|
} `yaml:"http2,omitempty"`
|
||||||
@@ -188,8 +189,11 @@ type Configuration struct {
|
|||||||
|
|
||||||
// Validation configures validation options for the registry.
|
// Validation configures validation options for the registry.
|
||||||
Validation struct {
|
Validation struct {
|
||||||
// Enabled enables the other options in this section.
|
// Enabled enables the other options in this section. This field is
|
||||||
|
// deprecated in favor of Disabled.
|
||||||
Enabled bool `yaml:"enabled,omitempty"`
|
Enabled bool `yaml:"enabled,omitempty"`
|
||||||
|
// Disabled disables the other options in this section.
|
||||||
|
Disabled bool `yaml:"disabled,omitempty"`
|
||||||
// Manifests configures manifest validation.
|
// Manifests configures manifest validation.
|
||||||
Manifests struct {
|
Manifests struct {
|
||||||
// URLs configures validation for URLs in pushed manifests.
|
// URLs configures validation for URLs in pushed manifests.
|
||||||
@@ -232,7 +236,7 @@ type LogHook struct {
|
|||||||
// Levels set which levels of log message will let hook executed.
|
// Levels set which levels of log message will let hook executed.
|
||||||
Levels []string `yaml:"levels,omitempty"`
|
Levels []string `yaml:"levels,omitempty"`
|
||||||
|
|
||||||
// MailOptions allows user to configurate email parameters.
|
// MailOptions allows user to configure email parameters.
|
||||||
MailOptions MailOptions `yaml:"options,omitempty"`
|
MailOptions MailOptions `yaml:"options,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,7 +330,7 @@ type Health struct {
|
|||||||
type v0_1Configuration Configuration
|
type v0_1Configuration Configuration
|
||||||
|
|
||||||
// UnmarshalYAML implements the yaml.Unmarshaler interface
|
// UnmarshalYAML implements the yaml.Unmarshaler interface
|
||||||
// Unmarshals a string of the form X.Y into a Version, validating that X and Y can represent uints
|
// Unmarshals a string of the form X.Y into a Version, validating that X and Y can represent unsigned integers
|
||||||
func (version *Version) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
func (version *Version) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
var versionString string
|
var versionString string
|
||||||
err := unmarshal(&versionString)
|
err := unmarshal(&versionString)
|
||||||
@@ -624,7 +628,7 @@ func Parse(rd io.Reader) (*Configuration, error) {
|
|||||||
v0_1.Loglevel = Loglevel("info")
|
v0_1.Loglevel = Loglevel("info")
|
||||||
}
|
}
|
||||||
if v0_1.Storage.Type() == "" {
|
if v0_1.Storage.Type() == "" {
|
||||||
return nil, fmt.Errorf("No storage configuration provided")
|
return nil, errors.New("No storage configuration provided")
|
||||||
}
|
}
|
||||||
return (*Configuration)(v0_1), nil
|
return (*Configuration)(v0_1), nil
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/context/doc.go
generated
vendored
2
vendor/github.com/docker/distribution/context/doc.go
generated
vendored
@@ -64,7 +64,7 @@
|
|||||||
// Note that this only affects the new context, the previous context, with the
|
// Note that this only affects the new context, the previous context, with the
|
||||||
// version field, can be used independently. Put another way, the new logger,
|
// version field, can be used independently. Put another way, the new logger,
|
||||||
// added to the request context, is unique to that context and can have
|
// added to the request context, is unique to that context and can have
|
||||||
// request scoped varaibles.
|
// request scoped variables.
|
||||||
//
|
//
|
||||||
// HTTP Requests
|
// HTTP Requests
|
||||||
//
|
//
|
||||||
|
|||||||
6
vendor/github.com/docker/distribution/contrib/compose/README.md
generated
vendored
6
vendor/github.com/docker/distribution/contrib/compose/README.md
generated
vendored
@@ -123,13 +123,13 @@ to the 1.0 registry. Requests from newer clients will route to the 2.0 registry.
|
|||||||
|
|
||||||
4. Use `curl` to list the image in the registry.
|
4. Use `curl` to list the image in the registry.
|
||||||
|
|
||||||
$ curl -v -X GET http://localhost:32777/v2/registry1/tags/list
|
$ curl -v -X GET http://localhost:5000/v2/registry_one/tags/list
|
||||||
* Hostname was NOT found in DNS cache
|
* Hostname was NOT found in DNS cache
|
||||||
* Trying 127.0.0.1...
|
* Trying 127.0.0.1...
|
||||||
* Connected to localhost (127.0.0.1) port 32777 (#0)
|
* Connected to localhost (127.0.0.1) port 32777 (#0)
|
||||||
> GET /v2/registry1/tags/list HTTP/1.1
|
> GET /v2/registry1/tags/list HTTP/1.1
|
||||||
> User-Agent: curl/7.36.0
|
> User-Agent: curl/7.36.0
|
||||||
> Host: localhost:32777
|
> Host: localhost:5000
|
||||||
> Accept: */*
|
> Accept: */*
|
||||||
>
|
>
|
||||||
< HTTP/1.1 200 OK
|
< HTTP/1.1 200 OK
|
||||||
@@ -138,7 +138,7 @@ to the 1.0 registry. Requests from newer clients will route to the 2.0 registry.
|
|||||||
< Date: Tue, 14 Apr 2015 22:34:13 GMT
|
< Date: Tue, 14 Apr 2015 22:34:13 GMT
|
||||||
< Content-Length: 39
|
< Content-Length: 39
|
||||||
<
|
<
|
||||||
{"name":"registry1","tags":["latest"]}
|
{"name":"registry_one","tags":["latest"]}
|
||||||
* Connection #0 to host localhost left intact
|
* Connection #0 to host localhost left intact
|
||||||
|
|
||||||
This example refers to the specific port assigned to the 2.0 registry. You saw
|
This example refers to the specific port assigned to the 2.0 registry. You saw
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/contrib/docker-integration/docker-compose.yml
generated
vendored
2
vendor/github.com/docker/distribution/contrib/docker-integration/docker-compose.yml
generated
vendored
@@ -64,7 +64,7 @@ registryv2tokenoauthnotls:
|
|||||||
- ./tokenserver-oauth/certs/signing.cert:/etc/docker/registry/tokenbundle.pem
|
- ./tokenserver-oauth/certs/signing.cert:/etc/docker/registry/tokenbundle.pem
|
||||||
tokenserveroauth:
|
tokenserveroauth:
|
||||||
build: "tokenserver-oauth"
|
build: "tokenserver-oauth"
|
||||||
command: "--debug -addr 0.0.0.0:5559 -issuer registry-test -passwd .htpasswd -tlscert tls.cert -tlskey tls.key -key sign.key -realm http://auth.localregistry:5559"
|
command: "--debug -addr 0.0.0.0:5559 -issuer registry-test -passwd .htpasswd -tlscert tls.cert -tlskey tls.key -key sign.key -realm http://auth.localregistry:5559 -enforce-class"
|
||||||
ports:
|
ports:
|
||||||
- "5559"
|
- "5559"
|
||||||
malevolent:
|
malevolent:
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/contrib/docker-integration/golem.conf
generated
vendored
2
vendor/github.com/docker/distribution/contrib/docker-integration/golem.conf
generated
vendored
@@ -1,6 +1,6 @@
|
|||||||
[[suite]]
|
[[suite]]
|
||||||
dind=true
|
dind=true
|
||||||
images=[ "nginx:1.9", "dmcgowan/token-server:simple", "dmcgowan/token-server:oauth", "dmcgowan/malevolent:0.1.0" ]
|
images=[ "nginx:1.9", "dmcgowan/token-server:simple", "dmcgowan/token-server:oauth", "dmcgowan/malevolent:0.1.0", "dmcgowan/ncat:latest" ]
|
||||||
|
|
||||||
[[suite.pretest]]
|
[[suite.pretest]]
|
||||||
command="sh ./install_certs.sh /etc/generated_certs.d"
|
command="sh ./install_certs.sh /etc/generated_certs.d"
|
||||||
|
|||||||
30
vendor/github.com/docker/distribution/contrib/docker-integration/helpers.bash
generated
vendored
30
vendor/github.com/docker/distribution/contrib/docker-integration/helpers.bash
generated
vendored
@@ -32,18 +32,44 @@ function basic_auth_version_check() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
email="a@nowhere.com"
|
||||||
|
|
||||||
|
# docker_t_login calls login with email depending on version
|
||||||
|
function docker_t_login() {
|
||||||
|
# Only pass email field pre 1.11, no deprecation warning
|
||||||
|
parse_version "$GOLEM_DIND_VERSION"
|
||||||
|
v=$version
|
||||||
|
parse_version "1.11.0"
|
||||||
|
if [ "$v" -lt "$version" ]; then
|
||||||
|
run docker_t login -e $email $@
|
||||||
|
else
|
||||||
|
run docker_t login $@
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# login issues a login to docker to the provided server
|
# login issues a login to docker to the provided server
|
||||||
# uses user, password, and email variables set outside of function
|
# uses user, password, and email variables set outside of function
|
||||||
# requies bats
|
# requies bats
|
||||||
function login() {
|
function login() {
|
||||||
rm -f /root/.docker/config.json
|
rm -f /root/.docker/config.json
|
||||||
run docker_t login -u $user -p $password -e $email $1
|
|
||||||
|
docker_t_login -u $user -p $password $1
|
||||||
if [ "$status" -ne 0 ]; then
|
if [ "$status" -ne 0 ]; then
|
||||||
echo $output
|
echo $output
|
||||||
fi
|
fi
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
# Handle different deprecation warnings
|
||||||
|
parse_version "$GOLEM_DIND_VERSION"
|
||||||
|
v=$version
|
||||||
|
parse_version "1.11.0"
|
||||||
|
if [ "$v" -lt "$version" ]; then
|
||||||
# First line is WARNING about credential save or email deprecation (maybe both)
|
# First line is WARNING about credential save or email deprecation (maybe both)
|
||||||
[ "${lines[2]}" = "Login Succeeded" -o "${lines[1]}" = "Login Succeeded" ]
|
[ "${lines[2]}" = "Login Succeeded" -o "${lines[1]}" = "Login Succeeded" ]
|
||||||
|
else
|
||||||
|
[ "${lines[0]}" = "Login Succeeded" ]
|
||||||
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function login_oauth() {
|
function login_oauth() {
|
||||||
@@ -92,7 +118,7 @@ function docker_t() {
|
|||||||
docker exec dockerdaemon docker $@
|
docker exec dockerdaemon docker $@
|
||||||
}
|
}
|
||||||
|
|
||||||
# build reates a new docker image id from another image
|
# build creates a new docker image id from another image
|
||||||
function build() {
|
function build() {
|
||||||
docker exec -i dockerdaemon docker build --no-cache -t $1 - <<DOCKERFILE
|
docker exec -i dockerdaemon docker build --no-cache -t $1 - <<DOCKERFILE
|
||||||
FROM $2
|
FROM $2
|
||||||
|
|||||||
6
vendor/github.com/docker/distribution/contrib/docker-integration/malevolent.bats
generated
vendored
6
vendor/github.com/docker/distribution/contrib/docker-integration/malevolent.bats
generated
vendored
@@ -12,7 +12,7 @@ function setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@test "Test malevolent proxy pass through" {
|
@test "Test malevolent proxy pass through" {
|
||||||
docker_t tag -f $base:latest $host/$base/nochange:latest
|
docker_t tag $base:latest $host/$base/nochange:latest
|
||||||
run docker_t push $host/$base/nochange:latest
|
run docker_t push $host/$base/nochange:latest
|
||||||
echo $output
|
echo $output
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
@@ -26,7 +26,7 @@ function setup() {
|
|||||||
@test "Test malevolent image name change" {
|
@test "Test malevolent image name change" {
|
||||||
imagename="$host/$base/rename"
|
imagename="$host/$base/rename"
|
||||||
image="$imagename:lastest"
|
image="$imagename:lastest"
|
||||||
docker_t tag -f $base:latest $image
|
docker_t tag $base:latest $image
|
||||||
run docker_t push $image
|
run docker_t push $image
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
has_digest "$output"
|
has_digest "$output"
|
||||||
@@ -133,7 +133,7 @@ function setup() {
|
|||||||
has_digest "$output"
|
has_digest "$output"
|
||||||
|
|
||||||
image2="$host/$base/image2/alteredid:$poison2"
|
image2="$host/$base/image2/alteredid:$poison2"
|
||||||
docker_t tag -f $image1 $image2
|
docker_t tag $image1 $image2
|
||||||
run docker_t push $image2
|
run docker_t push $image2
|
||||||
echo "$output"
|
echo "$output"
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
|
|||||||
103
vendor/github.com/docker/distribution/contrib/docker-integration/plugins.bats
generated
vendored
Normal file
103
vendor/github.com/docker/distribution/contrib/docker-integration/plugins.bats
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
# This tests pushing and pulling plugins
|
||||||
|
|
||||||
|
load helpers
|
||||||
|
|
||||||
|
user="testuser"
|
||||||
|
password="testpassword"
|
||||||
|
base="hello-world"
|
||||||
|
|
||||||
|
#TODO: Create plugin image
|
||||||
|
function create_plugin() {
|
||||||
|
plugindir=$(mktemp -d)
|
||||||
|
|
||||||
|
cat - > $plugindir/config.json <<CONFIGJSON
|
||||||
|
{
|
||||||
|
"manifestVersion": "v0",
|
||||||
|
"description": "A test plugin for integration tests",
|
||||||
|
"entrypoint": ["/usr/bin/ncat", "-l", "-U", "//run/docker/plugins/plugin.sock"],
|
||||||
|
"interface" : {
|
||||||
|
"types": ["docker.volumedriver/1.0"],
|
||||||
|
"socket": "plugin.sock"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CONFIGJSON
|
||||||
|
|
||||||
|
cid=$(docker create dmcgowan/ncat:latest /bin/sh)
|
||||||
|
|
||||||
|
mkdir $plugindir/rootfs
|
||||||
|
|
||||||
|
docker export $cid | tar -x -C $plugindir/rootfs
|
||||||
|
|
||||||
|
docker rm $cid
|
||||||
|
|
||||||
|
daemontmp=$(docker exec dockerdaemon mktemp -d)
|
||||||
|
|
||||||
|
tar -c -C $plugindir . | docker exec -i dockerdaemon tar -x -C $daemontmp
|
||||||
|
|
||||||
|
docker exec dockerdaemon docker plugin create $1 $daemontmp
|
||||||
|
|
||||||
|
docker exec dockerdaemon rm -rf $daemontmp
|
||||||
|
|
||||||
|
rm -rf $plugindir
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Test plugin push and pull" {
|
||||||
|
version_check docker "$GOLEM_DIND_VERSION" "1.13.0-rc3"
|
||||||
|
version_check docker "$GOLEM_DISTRIBUTION_VERSION" "2.6.0"
|
||||||
|
|
||||||
|
login_oauth localregistry:5558
|
||||||
|
image="localregistry:5558/testuser/plugin1"
|
||||||
|
|
||||||
|
create_plugin $image
|
||||||
|
|
||||||
|
run docker_t plugin push $image
|
||||||
|
echo $output
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
docker_t plugin rm $image
|
||||||
|
|
||||||
|
docker_t plugin install --grant-all-permissions $image
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Test plugin push and failed image pull" {
|
||||||
|
version_check docker "$GOLEM_DIND_VERSION" "1.13.0-rc3"
|
||||||
|
version_check docker "$GOLEM_DISTRIBUTION_VERSION" "2.6.0"
|
||||||
|
|
||||||
|
|
||||||
|
login_oauth localregistry:5558
|
||||||
|
image="localregistry:5558/testuser/plugin-not-image"
|
||||||
|
|
||||||
|
create_plugin $image
|
||||||
|
|
||||||
|
run docker_t plugin push $image
|
||||||
|
echo $output
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
docker_t plugin rm $image
|
||||||
|
|
||||||
|
run docker_t pull $image
|
||||||
|
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Test image push and failed plugin pull" {
|
||||||
|
version_check docker "$GOLEM_DIND_VERSION" "1.13.0-rc3"
|
||||||
|
version_check docker "$GOLEM_DISTRIBUTION_VERSION" "2.6.0"
|
||||||
|
|
||||||
|
login_oauth localregistry:5558
|
||||||
|
image="localregistry:5558/testuser/image-not-plugin"
|
||||||
|
|
||||||
|
build $image "$base:latest"
|
||||||
|
|
||||||
|
run docker_t push $image
|
||||||
|
echo $output
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
docker_t rmi $image
|
||||||
|
|
||||||
|
run docker_t plugin install --grant-all-permissions $image
|
||||||
|
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
}
|
||||||
5
vendor/github.com/docker/distribution/contrib/docker-integration/run_multiversion.sh
generated
vendored
5
vendor/github.com/docker/distribution/contrib/docker-integration/run_multiversion.sh
generated
vendored
@@ -46,7 +46,6 @@ echo "Testing image $distimage with distribution version $distversion"
|
|||||||
# These images are defined in golem.conf
|
# These images are defined in golem.conf
|
||||||
time docker pull nginx:1.9
|
time docker pull nginx:1.9
|
||||||
time docker pull golang:1.6
|
time docker pull golang:1.6
|
||||||
time docker pull registry:0.9.1
|
|
||||||
time docker pull dmcgowan/token-server:simple
|
time docker pull dmcgowan/token-server:simple
|
||||||
time docker pull dmcgowan/token-server:oauth
|
time docker pull dmcgowan/token-server:oauth
|
||||||
time docker pull distribution/golem-runner:0.1-bats
|
time docker pull distribution/golem-runner:0.1-bats
|
||||||
@@ -54,11 +53,15 @@ time docker pull distribution/golem-runner:0.1-bats
|
|||||||
time docker pull docker:1.9.1-dind
|
time docker pull docker:1.9.1-dind
|
||||||
time docker pull docker:1.10.3-dind
|
time docker pull docker:1.10.3-dind
|
||||||
time docker pull docker:1.11.1-dind
|
time docker pull docker:1.11.1-dind
|
||||||
|
time docker pull docker:1.12.3-dind
|
||||||
|
time docker pull docker:1.13.0-rc5-dind
|
||||||
|
|
||||||
golem -cache $cachedir \
|
golem -cache $cachedir \
|
||||||
-i "golem-distribution:latest,$distimage,$distversion" \
|
-i "golem-distribution:latest,$distimage,$distversion" \
|
||||||
-i "golem-dind:latest,docker:1.9.1-dind,1.9.1" \
|
-i "golem-dind:latest,docker:1.9.1-dind,1.9.1" \
|
||||||
-i "golem-dind:latest,docker:1.10.3-dind,1.10.3" \
|
-i "golem-dind:latest,docker:1.10.3-dind,1.10.3" \
|
||||||
-i "golem-dind:latest,docker:1.11.1-dind,1.11.1" \
|
-i "golem-dind:latest,docker:1.11.1-dind,1.11.1" \
|
||||||
|
-i "golem-dind:latest,docker:1.12.3-dind,1.12.3" \
|
||||||
|
-i "golem-dind:latest,docker:1.13.0-rc5-dind,1.13.0" \
|
||||||
$DIR
|
$DIR
|
||||||
|
|
||||||
|
|||||||
19
vendor/github.com/docker/distribution/contrib/docker-integration/tls.bats
generated
vendored
19
vendor/github.com/docker/distribution/contrib/docker-integration/tls.bats
generated
vendored
@@ -12,14 +12,13 @@ image="${base}:latest"
|
|||||||
# Login information, should match values in nginx/test.passwd
|
# Login information, should match values in nginx/test.passwd
|
||||||
user=${TEST_USER:-"testuser"}
|
user=${TEST_USER:-"testuser"}
|
||||||
password=${TEST_PASSWORD:-"passpassword"}
|
password=${TEST_PASSWORD:-"passpassword"}
|
||||||
email="distribution@docker.com"
|
|
||||||
|
|
||||||
function setup() {
|
function setup() {
|
||||||
tempImage $image
|
tempImage $image
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Test valid certificates" {
|
@test "Test valid certificates" {
|
||||||
docker_t tag -f $image $hostname:5440/$image
|
docker_t tag $image $hostname:5440/$image
|
||||||
run docker_t push $hostname:5440/$image
|
run docker_t push $hostname:5440/$image
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
has_digest "$output"
|
has_digest "$output"
|
||||||
@@ -28,7 +27,7 @@ function setup() {
|
|||||||
@test "Test basic auth" {
|
@test "Test basic auth" {
|
||||||
basic_auth_version_check
|
basic_auth_version_check
|
||||||
login $hostname:5441
|
login $hostname:5441
|
||||||
docker_t tag -f $image $hostname:5441/$image
|
docker_t tag $image $hostname:5441/$image
|
||||||
run docker_t push $hostname:5441/$image
|
run docker_t push $hostname:5441/$image
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
has_digest "$output"
|
has_digest "$output"
|
||||||
@@ -60,14 +59,14 @@ function setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@test "Test TLS client auth" {
|
@test "Test TLS client auth" {
|
||||||
docker_t tag -f $image $hostname:5442/$image
|
docker_t tag $image $hostname:5442/$image
|
||||||
run docker_t push $hostname:5442/$image
|
run docker_t push $hostname:5442/$image
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
has_digest "$output"
|
has_digest "$output"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Test TLS client with invalid certificate authority fails" {
|
@test "Test TLS client with invalid certificate authority fails" {
|
||||||
docker_t tag -f $image $hostname:5443/$image
|
docker_t tag $image $hostname:5443/$image
|
||||||
run docker_t push $hostname:5443/$image
|
run docker_t push $hostname:5443/$image
|
||||||
[ "$status" -ne 0 ]
|
[ "$status" -ne 0 ]
|
||||||
}
|
}
|
||||||
@@ -75,14 +74,14 @@ function setup() {
|
|||||||
@test "Test basic auth with TLS client auth" {
|
@test "Test basic auth with TLS client auth" {
|
||||||
basic_auth_version_check
|
basic_auth_version_check
|
||||||
login $hostname:5444
|
login $hostname:5444
|
||||||
docker_t tag -f $image $hostname:5444/$image
|
docker_t tag $image $hostname:5444/$image
|
||||||
run docker_t push $hostname:5444/$image
|
run docker_t push $hostname:5444/$image
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
has_digest "$output"
|
has_digest "$output"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Test unknown certificate authority fails" {
|
@test "Test unknown certificate authority fails" {
|
||||||
docker_t tag -f $image $hostname:5445/$image
|
docker_t tag $image $hostname:5445/$image
|
||||||
run docker_t push $hostname:5445/$image
|
run docker_t push $hostname:5445/$image
|
||||||
[ "$status" -ne 0 ]
|
[ "$status" -ne 0 ]
|
||||||
}
|
}
|
||||||
@@ -90,19 +89,19 @@ function setup() {
|
|||||||
@test "Test basic auth with unknown certificate authority fails" {
|
@test "Test basic auth with unknown certificate authority fails" {
|
||||||
run login $hostname:5446
|
run login $hostname:5446
|
||||||
[ "$status" -ne 0 ]
|
[ "$status" -ne 0 ]
|
||||||
docker_t tag -f $image $hostname:5446/$image
|
docker_t tag $image $hostname:5446/$image
|
||||||
run docker_t push $hostname:5446/$image
|
run docker_t push $hostname:5446/$image
|
||||||
[ "$status" -ne 0 ]
|
[ "$status" -ne 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Test TLS client auth to server with unknown certificate authority fails" {
|
@test "Test TLS client auth to server with unknown certificate authority fails" {
|
||||||
docker_t tag -f $image $hostname:5447/$image
|
docker_t tag $image $hostname:5447/$image
|
||||||
run docker_t push $hostname:5447/$image
|
run docker_t push $hostname:5447/$image
|
||||||
[ "$status" -ne 0 ]
|
[ "$status" -ne 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Test failure to connect to server fails to fallback to SSLv3" {
|
@test "Test failure to connect to server fails to fallback to SSLv3" {
|
||||||
docker_t tag -f $image $hostname:5448/$image
|
docker_t tag $image $hostname:5448/$image
|
||||||
run docker_t push $hostname:5448/$image
|
run docker_t push $hostname:5448/$image
|
||||||
[ "$status" -ne 0 ]
|
[ "$status" -ne 0 ]
|
||||||
}
|
}
|
||||||
|
|||||||
16
vendor/github.com/docker/distribution/contrib/docker-integration/token.bats
generated
vendored
16
vendor/github.com/docker/distribution/contrib/docker-integration/token.bats
generated
vendored
@@ -6,23 +6,17 @@ load helpers
|
|||||||
|
|
||||||
user="testuser"
|
user="testuser"
|
||||||
password="testpassword"
|
password="testpassword"
|
||||||
email="a@nowhere.com"
|
|
||||||
base="hello-world"
|
base="hello-world"
|
||||||
|
|
||||||
@test "Test token server login" {
|
@test "Test token server login" {
|
||||||
run docker_t login -u $user -p $password -e $email localregistry:5554
|
login localregistry:5554
|
||||||
echo $output
|
|
||||||
[ "$status" -eq 0 ]
|
|
||||||
|
|
||||||
# First line is WARNING about credential save or email deprecation
|
|
||||||
[ "${lines[2]}" = "Login Succeeded" -o "${lines[1]}" = "Login Succeeded" ]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Test token server bad login" {
|
@test "Test token server bad login" {
|
||||||
run docker_t login -u "testuser" -p "badpassword" -e $email localregistry:5554
|
docker_t_login -u "testuser" -p "badpassword" localregistry:5554
|
||||||
[ "$status" -ne 0 ]
|
[ "$status" -ne 0 ]
|
||||||
|
|
||||||
run docker_t login -u "baduser" -p "testpassword" -e $email localregistry:5554
|
docker_t_login -u "baduser" -p "testpassword" localregistry:5554
|
||||||
[ "$status" -ne 0 ]
|
[ "$status" -ne 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,10 +52,10 @@ base="hello-world"
|
|||||||
@test "Test oauth token server bad login" {
|
@test "Test oauth token server bad login" {
|
||||||
version_check docker "$GOLEM_DIND_VERSION" "1.11.0"
|
version_check docker "$GOLEM_DIND_VERSION" "1.11.0"
|
||||||
|
|
||||||
run docker_t login -u "testuser" -p "badpassword" -e $email localregistry:5557
|
docker_t_login -u "testuser" -p "badpassword" -e $email localregistry:5557
|
||||||
[ "$status" -ne 0 ]
|
[ "$status" -ne 0 ]
|
||||||
|
|
||||||
run docker_t login -u "baduser" -p "testpassword" -e $email localregistry:5557
|
docker_t_login -u "baduser" -p "testpassword" -e $email localregistry:5557
|
||||||
[ "$status" -ne 0 ]
|
[ "$status" -ne 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM dmcgowan/token-server:oauth
|
FROM dmcgowan/token-server@sha256:5a6f76d3086cdf63249c77b521108387b49d85a30c5e1c4fe82fdf5ae3b76ba7
|
||||||
|
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM dmcgowan/token-server:simple
|
FROM dmcgowan/token-server@sha256:0eab50ebdff5b6b95b3addf4edbd8bd2f5b940f27b41b43c94afdf05863a81af
|
||||||
|
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
|
|
||||||
|
|||||||
139
vendor/github.com/docker/distribution/digest/digest.go
generated
vendored
139
vendor/github.com/docker/distribution/digest/digest.go
generated
vendored
@@ -1,139 +0,0 @@
|
|||||||
package digest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"hash"
|
|
||||||
"io"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// DigestSha256EmptyTar is the canonical sha256 digest of empty data
|
|
||||||
DigestSha256EmptyTar = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Digest allows simple protection of hex formatted digest strings, prefixed
|
|
||||||
// by their algorithm. Strings of type Digest have some guarantee of being in
|
|
||||||
// the correct format and it provides quick access to the components of a
|
|
||||||
// digest string.
|
|
||||||
//
|
|
||||||
// The following is an example of the contents of Digest types:
|
|
||||||
//
|
|
||||||
// sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc
|
|
||||||
//
|
|
||||||
// This allows to abstract the digest behind this type and work only in those
|
|
||||||
// terms.
|
|
||||||
type Digest string
|
|
||||||
|
|
||||||
// NewDigest returns a Digest from alg and a hash.Hash object.
|
|
||||||
func NewDigest(alg Algorithm, h hash.Hash) Digest {
|
|
||||||
return NewDigestFromBytes(alg, h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDigestFromBytes returns a new digest from the byte contents of p.
|
|
||||||
// Typically, this can come from hash.Hash.Sum(...) or xxx.SumXXX(...)
|
|
||||||
// functions. This is also useful for rebuilding digests from binary
|
|
||||||
// serializations.
|
|
||||||
func NewDigestFromBytes(alg Algorithm, p []byte) Digest {
|
|
||||||
return Digest(fmt.Sprintf("%s:%x", alg, p))
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDigestFromHex returns a Digest from alg and a the hex encoded digest.
|
|
||||||
func NewDigestFromHex(alg, hex string) Digest {
|
|
||||||
return Digest(fmt.Sprintf("%s:%s", alg, hex))
|
|
||||||
}
|
|
||||||
|
|
||||||
// DigestRegexp matches valid digest types.
|
|
||||||
var DigestRegexp = regexp.MustCompile(`[a-zA-Z0-9-_+.]+:[a-fA-F0-9]+`)
|
|
||||||
|
|
||||||
// DigestRegexpAnchored matches valid digest types, anchored to the start and end of the match.
|
|
||||||
var DigestRegexpAnchored = regexp.MustCompile(`^` + DigestRegexp.String() + `$`)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrDigestInvalidFormat returned when digest format invalid.
|
|
||||||
ErrDigestInvalidFormat = fmt.Errorf("invalid checksum digest format")
|
|
||||||
|
|
||||||
// ErrDigestInvalidLength returned when digest has invalid length.
|
|
||||||
ErrDigestInvalidLength = fmt.Errorf("invalid checksum digest length")
|
|
||||||
|
|
||||||
// ErrDigestUnsupported returned when the digest algorithm is unsupported.
|
|
||||||
ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm")
|
|
||||||
)
|
|
||||||
|
|
||||||
// ParseDigest parses s and returns the validated digest object. An error will
|
|
||||||
// be returned if the format is invalid.
|
|
||||||
func ParseDigest(s string) (Digest, error) {
|
|
||||||
d := Digest(s)
|
|
||||||
|
|
||||||
return d, d.Validate()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromReader returns the most valid digest for the underlying content using
|
|
||||||
// the canonical digest algorithm.
|
|
||||||
func FromReader(rd io.Reader) (Digest, error) {
|
|
||||||
return Canonical.FromReader(rd)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromBytes digests the input and returns a Digest.
|
|
||||||
func FromBytes(p []byte) Digest {
|
|
||||||
return Canonical.FromBytes(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate checks that the contents of d is a valid digest, returning an
|
|
||||||
// error if not.
|
|
||||||
func (d Digest) Validate() error {
|
|
||||||
s := string(d)
|
|
||||||
|
|
||||||
if !DigestRegexpAnchored.MatchString(s) {
|
|
||||||
return ErrDigestInvalidFormat
|
|
||||||
}
|
|
||||||
|
|
||||||
i := strings.Index(s, ":")
|
|
||||||
if i < 0 {
|
|
||||||
return ErrDigestInvalidFormat
|
|
||||||
}
|
|
||||||
|
|
||||||
// case: "sha256:" with no hex.
|
|
||||||
if i+1 == len(s) {
|
|
||||||
return ErrDigestInvalidFormat
|
|
||||||
}
|
|
||||||
|
|
||||||
switch algorithm := Algorithm(s[:i]); algorithm {
|
|
||||||
case SHA256, SHA384, SHA512:
|
|
||||||
if algorithm.Size()*2 != len(s[i+1:]) {
|
|
||||||
return ErrDigestInvalidLength
|
|
||||||
}
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
return ErrDigestUnsupported
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Algorithm returns the algorithm portion of the digest. This will panic if
|
|
||||||
// the underlying digest is not in a valid format.
|
|
||||||
func (d Digest) Algorithm() Algorithm {
|
|
||||||
return Algorithm(d[:d.sepIndex()])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hex returns the hex digest portion of the digest. This will panic if the
|
|
||||||
// underlying digest is not in a valid format.
|
|
||||||
func (d Digest) Hex() string {
|
|
||||||
return string(d[d.sepIndex()+1:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d Digest) String() string {
|
|
||||||
return string(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d Digest) sepIndex() int {
|
|
||||||
i := strings.Index(string(d), ":")
|
|
||||||
|
|
||||||
if i < 0 {
|
|
||||||
panic("could not find ':' in digest: " + d)
|
|
||||||
}
|
|
||||||
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
82
vendor/github.com/docker/distribution/digest/digest_test.go
generated
vendored
82
vendor/github.com/docker/distribution/digest/digest_test.go
generated
vendored
@@ -1,82 +0,0 @@
|
|||||||
package digest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestParseDigest(t *testing.T) {
|
|
||||||
for _, testcase := range []struct {
|
|
||||||
input string
|
|
||||||
err error
|
|
||||||
algorithm Algorithm
|
|
||||||
hex string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
input: "sha256:e58fcf7418d4390dec8e8fb69d88c06ec07039d651fedd3aa72af9972e7d046b",
|
|
||||||
algorithm: "sha256",
|
|
||||||
hex: "e58fcf7418d4390dec8e8fb69d88c06ec07039d651fedd3aa72af9972e7d046b",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: "sha384:d3fc7881460b7e22e3d172954463dddd7866d17597e7248453c48b3e9d26d9596bf9c4a9cf8072c9d5bad76e19af801d",
|
|
||||||
algorithm: "sha384",
|
|
||||||
hex: "d3fc7881460b7e22e3d172954463dddd7866d17597e7248453c48b3e9d26d9596bf9c4a9cf8072c9d5bad76e19af801d",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// empty hex
|
|
||||||
input: "sha256:",
|
|
||||||
err: ErrDigestInvalidFormat,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// just hex
|
|
||||||
input: "d41d8cd98f00b204e9800998ecf8427e",
|
|
||||||
err: ErrDigestInvalidFormat,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// not hex
|
|
||||||
input: "sha256:d41d8cd98f00b204e9800m98ecf8427e",
|
|
||||||
err: ErrDigestInvalidFormat,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// too short
|
|
||||||
input: "sha256:abcdef0123456789",
|
|
||||||
err: ErrDigestInvalidLength,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// too short (from different algorithm)
|
|
||||||
input: "sha512:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789",
|
|
||||||
err: ErrDigestInvalidLength,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: "foo:d41d8cd98f00b204e9800998ecf8427e",
|
|
||||||
err: ErrDigestUnsupported,
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
digest, err := ParseDigest(testcase.input)
|
|
||||||
if err != testcase.err {
|
|
||||||
t.Fatalf("error differed from expected while parsing %q: %v != %v", testcase.input, err, testcase.err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if testcase.err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if digest.Algorithm() != testcase.algorithm {
|
|
||||||
t.Fatalf("incorrect algorithm for parsed digest: %q != %q", digest.Algorithm(), testcase.algorithm)
|
|
||||||
}
|
|
||||||
|
|
||||||
if digest.Hex() != testcase.hex {
|
|
||||||
t.Fatalf("incorrect hex for parsed digest: %q != %q", digest.Hex(), testcase.hex)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse string return value and check equality
|
|
||||||
newParsed, err := ParseDigest(digest.String())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error parsing input %q: %v", testcase.input, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if newParsed != digest {
|
|
||||||
t.Fatalf("expected equal: %q != %q", newParsed, digest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
155
vendor/github.com/docker/distribution/digest/digester.go
generated
vendored
155
vendor/github.com/docker/distribution/digest/digester.go
generated
vendored
@@ -1,155 +0,0 @@
|
|||||||
package digest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto"
|
|
||||||
"fmt"
|
|
||||||
"hash"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Algorithm identifies and implementation of a digester by an identifier.
|
|
||||||
// Note the that this defines both the hash algorithm used and the string
|
|
||||||
// encoding.
|
|
||||||
type Algorithm string
|
|
||||||
|
|
||||||
// supported digest types
|
|
||||||
const (
|
|
||||||
SHA256 Algorithm = "sha256" // sha256 with hex encoding
|
|
||||||
SHA384 Algorithm = "sha384" // sha384 with hex encoding
|
|
||||||
SHA512 Algorithm = "sha512" // sha512 with hex encoding
|
|
||||||
|
|
||||||
// Canonical is the primary digest algorithm used with the distribution
|
|
||||||
// project. Other digests may be used but this one is the primary storage
|
|
||||||
// digest.
|
|
||||||
Canonical = SHA256
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// TODO(stevvooe): Follow the pattern of the standard crypto package for
|
|
||||||
// registration of digests. Effectively, we are a registerable set and
|
|
||||||
// common symbol access.
|
|
||||||
|
|
||||||
// algorithms maps values to hash.Hash implementations. Other algorithms
|
|
||||||
// may be available but they cannot be calculated by the digest package.
|
|
||||||
algorithms = map[Algorithm]crypto.Hash{
|
|
||||||
SHA256: crypto.SHA256,
|
|
||||||
SHA384: crypto.SHA384,
|
|
||||||
SHA512: crypto.SHA512,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Available returns true if the digest type is available for use. If this
|
|
||||||
// returns false, New and Hash will return nil.
|
|
||||||
func (a Algorithm) Available() bool {
|
|
||||||
h, ok := algorithms[a]
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// check availability of the hash, as well
|
|
||||||
return h.Available()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a Algorithm) String() string {
|
|
||||||
return string(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size returns number of bytes returned by the hash.
|
|
||||||
func (a Algorithm) Size() int {
|
|
||||||
h, ok := algorithms[a]
|
|
||||||
if !ok {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return h.Size()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set implemented to allow use of Algorithm as a command line flag.
|
|
||||||
func (a *Algorithm) Set(value string) error {
|
|
||||||
if value == "" {
|
|
||||||
*a = Canonical
|
|
||||||
} else {
|
|
||||||
// just do a type conversion, support is queried with Available.
|
|
||||||
*a = Algorithm(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a new digester for the specified algorithm. If the algorithm
|
|
||||||
// does not have a digester implementation, nil will be returned. This can be
|
|
||||||
// checked by calling Available before calling New.
|
|
||||||
func (a Algorithm) New() Digester {
|
|
||||||
return &digester{
|
|
||||||
alg: a,
|
|
||||||
hash: a.Hash(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns a new hash as used by the algorithm. If not available, the
|
|
||||||
// method will panic. Check Algorithm.Available() before calling.
|
|
||||||
func (a Algorithm) Hash() hash.Hash {
|
|
||||||
if !a.Available() {
|
|
||||||
// NOTE(stevvooe): A missing hash is usually a programming error that
|
|
||||||
// must be resolved at compile time. We don't import in the digest
|
|
||||||
// package to allow users to choose their hash implementation (such as
|
|
||||||
// when using stevvooe/resumable or a hardware accelerated package).
|
|
||||||
//
|
|
||||||
// Applications that may want to resolve the hash at runtime should
|
|
||||||
// call Algorithm.Available before call Algorithm.Hash().
|
|
||||||
panic(fmt.Sprintf("%v not available (make sure it is imported)", a))
|
|
||||||
}
|
|
||||||
|
|
||||||
return algorithms[a].New()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromReader returns the digest of the reader using the algorithm.
|
|
||||||
func (a Algorithm) FromReader(rd io.Reader) (Digest, error) {
|
|
||||||
digester := a.New()
|
|
||||||
|
|
||||||
if _, err := io.Copy(digester.Hash(), rd); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return digester.Digest(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromBytes digests the input and returns a Digest.
|
|
||||||
func (a Algorithm) FromBytes(p []byte) Digest {
|
|
||||||
digester := a.New()
|
|
||||||
|
|
||||||
if _, err := digester.Hash().Write(p); err != nil {
|
|
||||||
// Writes to a Hash should never fail. None of the existing
|
|
||||||
// hash implementations in the stdlib or hashes vendored
|
|
||||||
// here can return errors from Write. Having a panic in this
|
|
||||||
// condition instead of having FromBytes return an error value
|
|
||||||
// avoids unnecessary error handling paths in all callers.
|
|
||||||
panic("write to hash function returned error: " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return digester.Digest()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(stevvooe): Allow resolution of verifiers using the digest type and
|
|
||||||
// this registration system.
|
|
||||||
|
|
||||||
// Digester calculates the digest of written data. Writes should go directly
|
|
||||||
// to the return value of Hash, while calling Digest will return the current
|
|
||||||
// value of the digest.
|
|
||||||
type Digester interface {
|
|
||||||
Hash() hash.Hash // provides direct access to underlying hash instance.
|
|
||||||
Digest() Digest
|
|
||||||
}
|
|
||||||
|
|
||||||
// digester provides a simple digester definition that embeds a hasher.
|
|
||||||
type digester struct {
|
|
||||||
alg Algorithm
|
|
||||||
hash hash.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *digester) Hash() hash.Hash {
|
|
||||||
return d.hash
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *digester) Digest() Digest {
|
|
||||||
return NewDigest(d.alg, d.hash)
|
|
||||||
}
|
|
||||||
42
vendor/github.com/docker/distribution/digest/doc.go
generated
vendored
42
vendor/github.com/docker/distribution/digest/doc.go
generated
vendored
@@ -1,42 +0,0 @@
|
|||||||
// Package digest provides a generalized type to opaquely represent message
|
|
||||||
// digests and their operations within the registry. The Digest type is
|
|
||||||
// designed to serve as a flexible identifier in a content-addressable system.
|
|
||||||
// More importantly, it provides tools and wrappers to work with
|
|
||||||
// hash.Hash-based digests with little effort.
|
|
||||||
//
|
|
||||||
// Basics
|
|
||||||
//
|
|
||||||
// The format of a digest is simply a string with two parts, dubbed the
|
|
||||||
// "algorithm" and the "digest", separated by a colon:
|
|
||||||
//
|
|
||||||
// <algorithm>:<digest>
|
|
||||||
//
|
|
||||||
// An example of a sha256 digest representation follows:
|
|
||||||
//
|
|
||||||
// sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc
|
|
||||||
//
|
|
||||||
// In this case, the string "sha256" is the algorithm and the hex bytes are
|
|
||||||
// the "digest".
|
|
||||||
//
|
|
||||||
// Because the Digest type is simply a string, once a valid Digest is
|
|
||||||
// obtained, comparisons are cheap, quick and simple to express with the
|
|
||||||
// standard equality operator.
|
|
||||||
//
|
|
||||||
// Verification
|
|
||||||
//
|
|
||||||
// The main benefit of using the Digest type is simple verification against a
|
|
||||||
// given digest. The Verifier interface, modeled after the stdlib hash.Hash
|
|
||||||
// interface, provides a common write sink for digest verification. After
|
|
||||||
// writing is complete, calling the Verifier.Verified method will indicate
|
|
||||||
// whether or not the stream of bytes matches the target digest.
|
|
||||||
//
|
|
||||||
// Missing Features
|
|
||||||
//
|
|
||||||
// In addition to the above, we intend to add the following features to this
|
|
||||||
// package:
|
|
||||||
//
|
|
||||||
// 1. A Digester type that supports write sink digest calculation.
|
|
||||||
//
|
|
||||||
// 2. Suspend and resume of ongoing digest calculations to support efficient digest verification in the registry.
|
|
||||||
//
|
|
||||||
package digest
|
|
||||||
44
vendor/github.com/docker/distribution/digest/verifiers.go
generated
vendored
44
vendor/github.com/docker/distribution/digest/verifiers.go
generated
vendored
@@ -1,44 +0,0 @@
|
|||||||
package digest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"hash"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Verifier presents a general verification interface to be used with message
|
|
||||||
// digests and other byte stream verifications. Users instantiate a Verifier
|
|
||||||
// from one of the various methods, write the data under test to it then check
|
|
||||||
// the result with the Verified method.
|
|
||||||
type Verifier interface {
|
|
||||||
io.Writer
|
|
||||||
|
|
||||||
// Verified will return true if the content written to Verifier matches
|
|
||||||
// the digest.
|
|
||||||
Verified() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDigestVerifier returns a verifier that compares the written bytes
|
|
||||||
// against a passed in digest.
|
|
||||||
func NewDigestVerifier(d Digest) (Verifier, error) {
|
|
||||||
if err := d.Validate(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return hashVerifier{
|
|
||||||
hash: d.Algorithm().Hash(),
|
|
||||||
digest: d,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type hashVerifier struct {
|
|
||||||
digest Digest
|
|
||||||
hash hash.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hv hashVerifier) Write(p []byte) (n int, err error) {
|
|
||||||
return hv.hash.Write(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hv hashVerifier) Verified() bool {
|
|
||||||
return hv.digest == NewDigest(hv.digest.Algorithm(), hv.hash)
|
|
||||||
}
|
|
||||||
49
vendor/github.com/docker/distribution/digest/verifiers_test.go
generated
vendored
49
vendor/github.com/docker/distribution/digest/verifiers_test.go
generated
vendored
@@ -1,49 +0,0 @@
|
|||||||
package digest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/rand"
|
|
||||||
"io"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDigestVerifier(t *testing.T) {
|
|
||||||
p := make([]byte, 1<<20)
|
|
||||||
rand.Read(p)
|
|
||||||
digest := FromBytes(p)
|
|
||||||
|
|
||||||
verifier, err := NewDigestVerifier(digest)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error getting digest verifier: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
io.Copy(verifier, bytes.NewReader(p))
|
|
||||||
|
|
||||||
if !verifier.Verified() {
|
|
||||||
t.Fatalf("bytes not verified")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestVerifierUnsupportedDigest ensures that unsupported digest validation is
|
|
||||||
// flowing through verifier creation.
|
|
||||||
func TestVerifierUnsupportedDigest(t *testing.T) {
|
|
||||||
unsupported := Digest("bean:0123456789abcdef")
|
|
||||||
|
|
||||||
_, err := NewDigestVerifier(unsupported)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("expected error when creating verifier")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != ErrDigestUnsupported {
|
|
||||||
t.Fatalf("incorrect error for unsupported digest: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(stevvooe): Add benchmarks to measure bytes/second throughput for
|
|
||||||
// DigestVerifier.
|
|
||||||
//
|
|
||||||
// The relevant benchmark for comparison can be run with the following
|
|
||||||
// commands:
|
|
||||||
//
|
|
||||||
// go test -bench . crypto/sha1
|
|
||||||
//
|
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package digest
|
package digestset
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
digest "github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -44,7 +46,7 @@ func NewSet() *Set {
|
|||||||
// values or short values. This function does not test equality,
|
// values or short values. This function does not test equality,
|
||||||
// rather whether the second value could match against the first
|
// rather whether the second value could match against the first
|
||||||
// value.
|
// value.
|
||||||
func checkShortMatch(alg Algorithm, hex, shortAlg, shortHex string) bool {
|
func checkShortMatch(alg digest.Algorithm, hex, shortAlg, shortHex string) bool {
|
||||||
if len(hex) == len(shortHex) {
|
if len(hex) == len(shortHex) {
|
||||||
if hex != shortHex {
|
if hex != shortHex {
|
||||||
return false
|
return false
|
||||||
@@ -64,7 +66,7 @@ func checkShortMatch(alg Algorithm, hex, shortAlg, shortHex string) bool {
|
|||||||
// If no digests could be found ErrDigestNotFound will be returned
|
// If no digests could be found ErrDigestNotFound will be returned
|
||||||
// with an empty digest value. If multiple matches are found
|
// with an empty digest value. If multiple matches are found
|
||||||
// ErrDigestAmbiguous will be returned with an empty digest value.
|
// ErrDigestAmbiguous will be returned with an empty digest value.
|
||||||
func (dst *Set) Lookup(d string) (Digest, error) {
|
func (dst *Set) Lookup(d string) (digest.Digest, error) {
|
||||||
dst.mutex.RLock()
|
dst.mutex.RLock()
|
||||||
defer dst.mutex.RUnlock()
|
defer dst.mutex.RUnlock()
|
||||||
if len(dst.entries) == 0 {
|
if len(dst.entries) == 0 {
|
||||||
@@ -72,11 +74,11 @@ func (dst *Set) Lookup(d string) (Digest, error) {
|
|||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
searchFunc func(int) bool
|
searchFunc func(int) bool
|
||||||
alg Algorithm
|
alg digest.Algorithm
|
||||||
hex string
|
hex string
|
||||||
)
|
)
|
||||||
dgst, err := ParseDigest(d)
|
dgst, err := digest.Parse(d)
|
||||||
if err == ErrDigestInvalidFormat {
|
if err == digest.ErrDigestInvalidFormat {
|
||||||
hex = d
|
hex = d
|
||||||
searchFunc = func(i int) bool {
|
searchFunc = func(i int) bool {
|
||||||
return dst.entries[i].val >= d
|
return dst.entries[i].val >= d
|
||||||
@@ -108,7 +110,7 @@ func (dst *Set) Lookup(d string) (Digest, error) {
|
|||||||
// Add adds the given digest to the set. An error will be returned
|
// Add adds the given digest to the set. An error will be returned
|
||||||
// if the given digest is invalid. If the digest already exists in the
|
// if the given digest is invalid. If the digest already exists in the
|
||||||
// set, this operation will be a no-op.
|
// set, this operation will be a no-op.
|
||||||
func (dst *Set) Add(d Digest) error {
|
func (dst *Set) Add(d digest.Digest) error {
|
||||||
if err := d.Validate(); err != nil {
|
if err := d.Validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -139,7 +141,7 @@ func (dst *Set) Add(d Digest) error {
|
|||||||
// Remove removes the given digest from the set. An err will be
|
// Remove removes the given digest from the set. An err will be
|
||||||
// returned if the given digest is invalid. If the digest does
|
// returned if the given digest is invalid. If the digest does
|
||||||
// not exist in the set, this operation will be a no-op.
|
// not exist in the set, this operation will be a no-op.
|
||||||
func (dst *Set) Remove(d Digest) error {
|
func (dst *Set) Remove(d digest.Digest) error {
|
||||||
if err := d.Validate(); err != nil {
|
if err := d.Validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -167,10 +169,10 @@ func (dst *Set) Remove(d Digest) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// All returns all the digests in the set
|
// All returns all the digests in the set
|
||||||
func (dst *Set) All() []Digest {
|
func (dst *Set) All() []digest.Digest {
|
||||||
dst.mutex.RLock()
|
dst.mutex.RLock()
|
||||||
defer dst.mutex.RUnlock()
|
defer dst.mutex.RUnlock()
|
||||||
retValues := make([]Digest, len(dst.entries))
|
retValues := make([]digest.Digest, len(dst.entries))
|
||||||
for i := range dst.entries {
|
for i := range dst.entries {
|
||||||
retValues[i] = dst.entries[i].digest
|
retValues[i] = dst.entries[i].digest
|
||||||
}
|
}
|
||||||
@@ -183,10 +185,10 @@ func (dst *Set) All() []Digest {
|
|||||||
// entire value of digest if uniqueness cannot be achieved without the
|
// entire value of digest if uniqueness cannot be achieved without the
|
||||||
// full value. This function will attempt to make short codes as short
|
// full value. This function will attempt to make short codes as short
|
||||||
// as possible to be unique.
|
// as possible to be unique.
|
||||||
func ShortCodeTable(dst *Set, length int) map[Digest]string {
|
func ShortCodeTable(dst *Set, length int) map[digest.Digest]string {
|
||||||
dst.mutex.RLock()
|
dst.mutex.RLock()
|
||||||
defer dst.mutex.RUnlock()
|
defer dst.mutex.RUnlock()
|
||||||
m := make(map[Digest]string, len(dst.entries))
|
m := make(map[digest.Digest]string, len(dst.entries))
|
||||||
l := length
|
l := length
|
||||||
resetIdx := 0
|
resetIdx := 0
|
||||||
for i := 0; i < len(dst.entries); i++ {
|
for i := 0; i < len(dst.entries); i++ {
|
||||||
@@ -222,9 +224,9 @@ func ShortCodeTable(dst *Set, length int) map[Digest]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type digestEntry struct {
|
type digestEntry struct {
|
||||||
alg Algorithm
|
alg digest.Algorithm
|
||||||
val string
|
val string
|
||||||
digest Digest
|
digest digest.Digest
|
||||||
}
|
}
|
||||||
|
|
||||||
type digestEntries []*digestEntry
|
type digestEntries []*digestEntry
|
||||||
@@ -1,20 +1,23 @@
|
|||||||
package digest
|
package digestset
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
_ "crypto/sha512"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
digest "github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func assertEqualDigests(t *testing.T, d1, d2 Digest) {
|
func assertEqualDigests(t *testing.T, d1, d2 digest.Digest) {
|
||||||
if d1 != d2 {
|
if d1 != d2 {
|
||||||
t.Fatalf("Digests do not match:\n\tActual: %s\n\tExpected: %s", d1, d2)
|
t.Fatalf("Digests do not match:\n\tActual: %s\n\tExpected: %s", d1, d2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLookup(t *testing.T) {
|
func TestLookup(t *testing.T) {
|
||||||
digests := []Digest{
|
digests := []digest.Digest{
|
||||||
"sha256:1234511111111111111111111111111111111111111111111111111111111111",
|
"sha256:1234511111111111111111111111111111111111111111111111111111111111",
|
||||||
"sha256:1234111111111111111111111111111111111111111111111111111111111111",
|
"sha256:1234111111111111111111111111111111111111111111111111111111111111",
|
||||||
"sha256:1234611111111111111111111111111111111111111111111111111111111111",
|
"sha256:1234611111111111111111111111111111111111111111111111111111111111",
|
||||||
@@ -88,7 +91,7 @@ func TestLookup(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAddDuplication(t *testing.T) {
|
func TestAddDuplication(t *testing.T) {
|
||||||
digests := []Digest{
|
digests := []digest.Digest{
|
||||||
"sha256:1234111111111111111111111111111111111111111111111111111111111111",
|
"sha256:1234111111111111111111111111111111111111111111111111111111111111",
|
||||||
"sha256:1234511111111111111111111111111111111111111111111111111111111111",
|
"sha256:1234511111111111111111111111111111111111111111111111111111111111",
|
||||||
"sha256:1234611111111111111111111111111111111111111111111111111111111111",
|
"sha256:1234611111111111111111111111111111111111111111111111111111111111",
|
||||||
@@ -110,7 +113,7 @@ func TestAddDuplication(t *testing.T) {
|
|||||||
t.Fatal("Invalid dset size")
|
t.Fatal("Invalid dset size")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := dset.Add(Digest("sha256:1234511111111111111111111111111111111111111111111111111111111111")); err != nil {
|
if err := dset.Add(digest.Digest("sha256:1234511111111111111111111111111111111111111111111111111111111111")); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +121,7 @@ func TestAddDuplication(t *testing.T) {
|
|||||||
t.Fatal("Duplicate digest insert allowed")
|
t.Fatal("Duplicate digest insert allowed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := dset.Add(Digest("sha384:123451111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")); err != nil {
|
if err := dset.Add(digest.Digest("sha384:123451111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +173,7 @@ func TestAll(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
all := map[Digest]struct{}{}
|
all := map[digest.Digest]struct{}{}
|
||||||
for _, dgst := range dset.All() {
|
for _, dgst := range dset.All() {
|
||||||
all[dgst] = struct{}{}
|
all[dgst] = struct{}{}
|
||||||
}
|
}
|
||||||
@@ -194,7 +197,7 @@ func assertEqualShort(t *testing.T, actual, expected string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestShortCodeTable(t *testing.T) {
|
func TestShortCodeTable(t *testing.T) {
|
||||||
digests := []Digest{
|
digests := []digest.Digest{
|
||||||
"sha256:1234111111111111111111111111111111111111111111111111111111111111",
|
"sha256:1234111111111111111111111111111111111111111111111111111111111111",
|
||||||
"sha256:1234511111111111111111111111111111111111111111111111111111111111",
|
"sha256:1234511111111111111111111111111111111111111111111111111111111111",
|
||||||
"sha256:1234611111111111111111111111111111111111111111111111111111111111",
|
"sha256:1234611111111111111111111111111111111111111111111111111111111111",
|
||||||
@@ -227,15 +230,15 @@ func TestShortCodeTable(t *testing.T) {
|
|||||||
assertEqualShort(t, dump[digests[7]], "653")
|
assertEqualShort(t, dump[digests[7]], "653")
|
||||||
}
|
}
|
||||||
|
|
||||||
func createDigests(count int) ([]Digest, error) {
|
func createDigests(count int) ([]digest.Digest, error) {
|
||||||
r := rand.New(rand.NewSource(25823))
|
r := rand.New(rand.NewSource(25823))
|
||||||
digests := make([]Digest, count)
|
digests := make([]digest.Digest, count)
|
||||||
for i := range digests {
|
for i := range digests {
|
||||||
h := sha256.New()
|
h := sha256.New()
|
||||||
if err := binary.Write(h, binary.BigEndian, r.Int63()); err != nil {
|
if err := binary.Write(h, binary.BigEndian, r.Int63()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
digests[i] = NewDigest("sha256", h)
|
digests[i] = digest.NewDigest("sha256", h)
|
||||||
}
|
}
|
||||||
return digests, nil
|
return digests, nil
|
||||||
}
|
}
|
||||||
52
vendor/github.com/docker/distribution/docs/architecture.md
generated
vendored
Normal file
52
vendor/github.com/docker/distribution/docs/architecture.md
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
published: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# Architecture
|
||||||
|
|
||||||
|
## Design
|
||||||
|
**TODO(stevvooe):** Discuss the architecture of the registry, internally and externally, in a few different deployment scenarios.
|
||||||
|
|
||||||
|
### Eventual Consistency
|
||||||
|
|
||||||
|
> **NOTE:** This section belongs somewhere, perhaps in a design document. We
|
||||||
|
> are leaving this here so the information is not lost.
|
||||||
|
|
||||||
|
Running the registry on eventually consistent backends has been part of the
|
||||||
|
design from the beginning. This section covers some of the approaches to
|
||||||
|
dealing with this reality.
|
||||||
|
|
||||||
|
There are a few classes of issues that we need to worry about when
|
||||||
|
implementing something on top of the storage drivers:
|
||||||
|
|
||||||
|
1. Read-After-Write consistency (see this [article on
|
||||||
|
s3](http://shlomoswidler.com/2009/12/read-after-write-consistency-in-amazon.html)).
|
||||||
|
2. [Write-Write Conflicts](http://en.wikipedia.org/wiki/Write%E2%80%93write_conflict).
|
||||||
|
|
||||||
|
In reality, the registry must worry about these kinds of errors when doing the
|
||||||
|
following:
|
||||||
|
|
||||||
|
1. Accepting data into a temporary upload file may not have latest data block
|
||||||
|
yet (read-after-write).
|
||||||
|
2. Moving uploaded data into its blob location (write-write race).
|
||||||
|
3. Modifying the "current" manifest for given tag (write-write race).
|
||||||
|
4. A whole slew of operations around deletes (read-after-write, delete-write
|
||||||
|
races, garbage collection, etc.).
|
||||||
|
|
||||||
|
The backend path layout employs a few techniques to avoid these problems:
|
||||||
|
|
||||||
|
1. Large writes are done to private upload directories. This alleviates most
|
||||||
|
of the corruption potential under multiple writers by avoiding multiple
|
||||||
|
writers.
|
||||||
|
2. Constraints in storage driver implementations, such as support for writing
|
||||||
|
after the end of a file to extend it.
|
||||||
|
3. Digest verification to avoid data corruption.
|
||||||
|
4. Manifest files are stored by digest and cannot change.
|
||||||
|
5. All other non-content files (links, hashes, etc.) are written as an atomic
|
||||||
|
unit. Anything that requires additions and deletions is broken out into
|
||||||
|
separate "files". Last writer still wins.
|
||||||
|
|
||||||
|
Unfortunately, one must play this game when trying to build something like
|
||||||
|
this on top of eventually consistent storage systems. If we run into serious
|
||||||
|
problems, we can wrap the storagedrivers in a shared consistency layer but
|
||||||
|
that would increase complexity and hinder registry cluster performance.
|
||||||
29
vendor/github.com/docker/distribution/docs/configuration.md
generated
vendored
29
vendor/github.com/docker/distribution/docs/configuration.md
generated
vendored
@@ -223,9 +223,9 @@ notifications:
|
|||||||
disabled: false
|
disabled: false
|
||||||
url: https://my.listener.com/event
|
url: https://my.listener.com/event
|
||||||
headers: <http.Header>
|
headers: <http.Header>
|
||||||
timeout: 500
|
timeout: 1s
|
||||||
threshold: 5
|
threshold: 10
|
||||||
backoff: 1000
|
backoff: 1s
|
||||||
ignoredmediatypes:
|
ignoredmediatypes:
|
||||||
- application/octet-stream
|
- application/octet-stream
|
||||||
redis:
|
redis:
|
||||||
@@ -268,7 +268,6 @@ compatibility:
|
|||||||
schema1:
|
schema1:
|
||||||
signingkeyfile: /etc/registry/key.json
|
signingkeyfile: /etc/registry/key.json
|
||||||
validation:
|
validation:
|
||||||
enabled: true
|
|
||||||
manifests:
|
manifests:
|
||||||
urls:
|
urls:
|
||||||
allow:
|
allow:
|
||||||
@@ -553,7 +552,7 @@ The `auth` option is **optional**. Possible auth providers include:
|
|||||||
|
|
||||||
- [`silly`](#silly)
|
- [`silly`](#silly)
|
||||||
- [`token`](#token)
|
- [`token`](#token)
|
||||||
- [`htpasswd`](#token)
|
- [`htpasswd`](#htpasswd)
|
||||||
|
|
||||||
You can configure only one authentication provider.
|
You can configure only one authentication provider.
|
||||||
|
|
||||||
@@ -817,9 +816,9 @@ notifications:
|
|||||||
disabled: false
|
disabled: false
|
||||||
url: https://my.listener.com/event
|
url: https://my.listener.com/event
|
||||||
headers: <http.Header>
|
headers: <http.Header>
|
||||||
timeout: 500
|
timeout: 1s
|
||||||
threshold: 5
|
threshold: 10
|
||||||
backoff: 1000
|
backoff: 1s
|
||||||
ignoredmediatypes:
|
ignoredmediatypes:
|
||||||
- application/octet-stream
|
- application/octet-stream
|
||||||
```
|
```
|
||||||
@@ -948,7 +947,7 @@ a file.
|
|||||||
| Parameter | Required | Description |
|
| Parameter | Required | Description |
|
||||||
|-----------|----------|-------------------------------------------------------|
|
|-----------|----------|-------------------------------------------------------|
|
||||||
| `file` | yes | The path to check for existence of a file. |
|
| `file` | yes | The path to check for existence of a file. |
|
||||||
| `interval`| no | How long to wait before repeating the check. A positive integer and an optional suffix indicating the unit of time. The suffix is one of `ns`, `us`, `ms`, `s`, `m`, or `h`. Defaults to `10s` if the value is omitted. |
|
| `interval`| no | How long to wait before repeating the check. A positive integer and an optional suffix indicating the unit of time. The suffix is one of `ns`, `us`, `ms`, `s`, `m`, or `h`. Defaults to `10s` if the value is omitted. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |
|
||||||
|
|
||||||
### `http`
|
### `http`
|
||||||
|
|
||||||
@@ -1028,7 +1027,6 @@ features. Each subsection defines such a feature with configurable behavior.
|
|||||||
|
|
||||||
```none
|
```none
|
||||||
validation:
|
validation:
|
||||||
enabled: true
|
|
||||||
manifests:
|
manifests:
|
||||||
urls:
|
urls:
|
||||||
allow:
|
allow:
|
||||||
@@ -1037,14 +1035,15 @@ validation:
|
|||||||
- ^https?://www\.example\.com/
|
- ^https?://www\.example\.com/
|
||||||
```
|
```
|
||||||
|
|
||||||
### `enabled`
|
### `disabled`
|
||||||
|
|
||||||
Use the `enabled` flag to enable the other options in the `validation`
|
The `disabled` flag disables the other options in the `validation`
|
||||||
section. They are disabled by default.
|
section. They are enabled by default. This option deprecates the `enabled` flag.
|
||||||
|
|
||||||
### `manifests`
|
### `manifests`
|
||||||
|
|
||||||
Use the `manifest` subsection to configure manifest validation.
|
Use the `manifests` subsection to configure validation of manifests. If
|
||||||
|
`disabled` is `false`, the validation allows nothing.
|
||||||
|
|
||||||
#### `urls`
|
#### `urls`
|
||||||
|
|
||||||
@@ -1110,7 +1109,7 @@ middleware:
|
|||||||
baseurl: http://d111111abcdef8.cloudfront.net
|
baseurl: http://d111111abcdef8.cloudfront.net
|
||||||
privatekey: /path/to/asecret.pem
|
privatekey: /path/to/asecret.pem
|
||||||
keypairid: asecret
|
keypairid: asecret
|
||||||
duration: 60
|
duration: 60s
|
||||||
```
|
```
|
||||||
|
|
||||||
See the configuration reference for [Cloudfront](#cloudfront) for more
|
See the configuration reference for [Cloudfront](#cloudfront) for more
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/docs/spec/api.md
generated
vendored
2
vendor/github.com/docker/distribution/docs/spec/api.md
generated
vendored
@@ -795,7 +795,7 @@ Note that the upload url will not be available forever. If the upload uuid is
|
|||||||
unknown to the registry, a `404 Not Found` response will be returned and the
|
unknown to the registry, a `404 Not Found` response will be returned and the
|
||||||
client must restart the upload process.
|
client must restart the upload process.
|
||||||
|
|
||||||
### Deleting a Layer
|
#### Deleting a Layer
|
||||||
|
|
||||||
A layer may be deleted from the registry via its `name` and `digest`. A
|
A layer may be deleted from the registry via its `name` and `digest`. A
|
||||||
delete may be issued with the following request format:
|
delete may be issued with the following request format:
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/docs/spec/api.md.tmpl
generated
vendored
2
vendor/github.com/docker/distribution/docs/spec/api.md.tmpl
generated
vendored
@@ -795,7 +795,7 @@ Note that the upload url will not be available forever. If the upload uuid is
|
|||||||
unknown to the registry, a `404 Not Found` response will be returned and the
|
unknown to the registry, a `404 Not Found` response will be returned and the
|
||||||
client must restart the upload process.
|
client must restart the upload process.
|
||||||
|
|
||||||
### Deleting a Layer
|
#### Deleting a Layer
|
||||||
|
|
||||||
A layer may be deleted from the registry via its `name` and `digest`. A
|
A layer may be deleted from the registry via its `name` and `digest`. A
|
||||||
delete may be issued with the following request format:
|
delete may be issued with the following request format:
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/docs/spec/manifest-v2-1.md
generated
vendored
2
vendor/github.com/docker/distribution/docs/spec/manifest-v2-1.md
generated
vendored
@@ -6,7 +6,7 @@ keywords: ["registry, on-prem, images, tags, repository, distribution, api, adva
|
|||||||
|
|
||||||
# Image Manifest Version 2, Schema 1
|
# Image Manifest Version 2, Schema 1
|
||||||
|
|
||||||
This document outlines the format of of the V2 image manifest. The image
|
This document outlines the format of the V2 image manifest. The image
|
||||||
manifest described herein was introduced in the Docker daemon in the [v1.3.0
|
manifest described herein was introduced in the Docker daemon in the [v1.3.0
|
||||||
release](https://github.com/docker/docker/commit/9f482a66ab37ec396ac61ed0c00d59122ac07453).
|
release](https://github.com/docker/docker/commit/9f482a66ab37ec396ac61ed0c00d59122ac07453).
|
||||||
It is a provisional manifest to provide a compatibility with the [V1 Image
|
It is a provisional manifest to provide a compatibility with the [V1 Image
|
||||||
|
|||||||
10
vendor/github.com/docker/distribution/docs/spec/manifest-v2-2.md
generated
vendored
10
vendor/github.com/docker/distribution/docs/spec/manifest-v2-2.md
generated
vendored
@@ -6,7 +6,7 @@ keywords: ["registry, on-prem, images, tags, repository, distribution, api, adva
|
|||||||
|
|
||||||
# Image Manifest Version 2, Schema 2
|
# Image Manifest Version 2, Schema 2
|
||||||
|
|
||||||
This document outlines the format of of the V2 image manifest, schema version 2.
|
This document outlines the format of the V2 image manifest, schema version 2.
|
||||||
The original (and provisional) image manifest for V2 (schema 1), was introduced
|
The original (and provisional) image manifest for V2 (schema 1), was introduced
|
||||||
in the Docker daemon in the [v1.3.0
|
in the Docker daemon in the [v1.3.0
|
||||||
release](https://github.com/docker/docker/commit/9f482a66ab37ec396ac61ed0c00d59122ac07453)
|
release](https://github.com/docker/docker/commit/9f482a66ab37ec396ac61ed0c00d59122ac07453)
|
||||||
@@ -60,8 +60,8 @@ image manifest based on the Content-Type returned in the HTTP response.
|
|||||||
- **`mediaType`** *string*
|
- **`mediaType`** *string*
|
||||||
|
|
||||||
The MIME type of the referenced object. This will generally be
|
The MIME type of the referenced object. This will generally be
|
||||||
`application/vnd.docker.image.manifest.v2+json`, but it could also
|
`application/vnd.docker.distribution.manifest.v2+json`, but it could also
|
||||||
be `application/vnd.docker.image.manifest.v1+json` if the manifest
|
be `application/vnd.docker.distribution.manifest.v1+json` if the manifest
|
||||||
list references a legacy schema-1 manifest.
|
list references a legacy schema-1 manifest.
|
||||||
|
|
||||||
- **`size`** *int*
|
- **`size`** *int*
|
||||||
@@ -123,7 +123,7 @@ image manifest based on the Content-Type returned in the HTTP response.
|
|||||||
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
|
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
|
||||||
"manifests": [
|
"manifests": [
|
||||||
{
|
{
|
||||||
"mediaType": "application/vnd.docker.image.manifest.v2+json",
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||||||
"size": 7143,
|
"size": 7143,
|
||||||
"digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
|
"digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
|
||||||
"platform": {
|
"platform": {
|
||||||
@@ -132,7 +132,7 @@ image manifest based on the Content-Type returned in the HTTP response.
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"mediaType": "application/vnd.docker.image.manifest.v2+json",
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||||||
"size": 7682,
|
"size": 7682,
|
||||||
"digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270",
|
"digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270",
|
||||||
"platform": {
|
"platform": {
|
||||||
|
|||||||
4
vendor/github.com/docker/distribution/errors.go
generated
vendored
4
vendor/github.com/docker/distribution/errors.go
generated
vendored
@@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrAccessDenied is returned when an access to a requested resource is
|
// ErrAccessDenied is returned when an access to a requested resource is
|
||||||
@@ -77,7 +77,7 @@ func (err ErrManifestUnknownRevision) Error() string {
|
|||||||
type ErrManifestUnverified struct{}
|
type ErrManifestUnverified struct{}
|
||||||
|
|
||||||
func (ErrManifestUnverified) Error() string {
|
func (ErrManifestUnverified) Error() string {
|
||||||
return fmt.Sprintf("unverified manifest")
|
return "unverified manifest"
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrManifestVerification provides a type to collect errors encountered
|
// ErrManifestVerification provides a type to collect errors encountered
|
||||||
|
|||||||
15
vendor/github.com/docker/distribution/health/checks/checks.go
generated
vendored
15
vendor/github.com/docker/distribution/health/checks/checks.go
generated
vendored
@@ -2,9 +2,11 @@ package checks
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -15,10 +17,19 @@ import (
|
|||||||
// if the file exists.
|
// if the file exists.
|
||||||
func FileChecker(f string) health.Checker {
|
func FileChecker(f string) health.Checker {
|
||||||
return health.CheckFunc(func() error {
|
return health.CheckFunc(func() error {
|
||||||
if _, err := os.Stat(f); err == nil {
|
absoluteFilePath, err := filepath.Abs(f)
|
||||||
return errors.New("file exists")
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get absolute path for %q: %v", f, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = os.Stat(absoluteFilePath)
|
||||||
|
if err == nil {
|
||||||
|
return errors.New("file exists")
|
||||||
|
} else if os.IsNotExist(err) {
|
||||||
return nil
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8
vendor/github.com/docker/distribution/health/doc.go
generated
vendored
8
vendor/github.com/docker/distribution/health/doc.go
generated
vendored
@@ -24,7 +24,7 @@
|
|||||||
// "manual" checks that allow the service to quickly be brought in/out of
|
// "manual" checks that allow the service to quickly be brought in/out of
|
||||||
// rotation.
|
// rotation.
|
||||||
//
|
//
|
||||||
// import _ "github.com/docker/distribution/registry/health/api"
|
// import _ "github.com/docker/distribution/health/api"
|
||||||
//
|
//
|
||||||
// # curl localhost:5001/debug/health
|
// # curl localhost:5001/debug/health
|
||||||
// {}
|
// {}
|
||||||
@@ -122,6 +122,12 @@
|
|||||||
// # curl localhost:5001/debug/health
|
// # curl localhost:5001/debug/health
|
||||||
// {"fileChecker":"file exists"}
|
// {"fileChecker":"file exists"}
|
||||||
//
|
//
|
||||||
|
// FileChecker only accepts absolute or relative file path. It does not work
|
||||||
|
// properly with tilde(~). You should make sure that the application has
|
||||||
|
// proper permission(read and execute permission for directory along with
|
||||||
|
// the specified file path). Otherwise, the FileChecker will report error
|
||||||
|
// and file health check is not ok.
|
||||||
|
//
|
||||||
// You could also test the connectivity to a downstream service by using a
|
// You could also test the connectivity to a downstream service by using a
|
||||||
// "HTTPChecker", but ensure that you only mark the test unhealthy if there
|
// "HTTPChecker", but ensure that you only mark the test unhealthy if there
|
||||||
// are a minimum of two failures in a row:
|
// are a minimum of two failures in a row:
|
||||||
|
|||||||
4
vendor/github.com/docker/distribution/health/health_test.go
generated
vendored
4
vendor/github.com/docker/distribution/health/health_test.go
generated
vendored
@@ -25,8 +25,8 @@ func TestReturns200IfThereAreNoChecks(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestReturns500IfThereAreErrorChecks ensures that the result code of the
|
// TestReturns503IfThereAreErrorChecks ensures that the result code of the
|
||||||
// health endpoint is 500 if there are health checks with errors
|
// health endpoint is 503 if there are health checks with errors.
|
||||||
func TestReturns503IfThereAreErrorChecks(t *testing.T) {
|
func TestReturns503IfThereAreErrorChecks(t *testing.T) {
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
|||||||
4
vendor/github.com/docker/distribution/manifest/manifestlist/manifestlist.go
generated
vendored
4
vendor/github.com/docker/distribution/manifest/manifestlist/manifestlist.go
generated
vendored
@@ -6,8 +6,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/manifest"
|
"github.com/docker/distribution/manifest"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MediaTypeManifestList specifies the mediaType for manifest lists.
|
// MediaTypeManifestList specifies the mediaType for manifest lists.
|
||||||
@@ -81,7 +81,7 @@ type ManifestList struct {
|
|||||||
Manifests []ManifestDescriptor `json:"manifests"`
|
Manifests []ManifestDescriptor `json:"manifests"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// References returnes the distribution descriptors for the referenced image
|
// References returns the distribution descriptors for the referenced image
|
||||||
// manifests.
|
// manifests.
|
||||||
func (m ManifestList) References() []distribution.Descriptor {
|
func (m ManifestList) References() []distribution.Descriptor {
|
||||||
dependencies := make([]distribution.Descriptor, len(m.Manifests))
|
dependencies := make([]distribution.Descriptor, len(m.Manifests))
|
||||||
|
|||||||
11
vendor/github.com/docker/distribution/manifest/schema1/config_builder.go
generated
vendored
11
vendor/github.com/docker/distribution/manifest/schema1/config_builder.go
generated
vendored
@@ -9,10 +9,10 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/manifest"
|
"github.com/docker/distribution/manifest"
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/libtrust"
|
"github.com/docker/libtrust"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
type diffID digest.Digest
|
type diffID digest.Digest
|
||||||
@@ -240,8 +240,13 @@ func (mb *configManifestBuilder) emptyTar(ctx context.Context) (digest.Digest, e
|
|||||||
|
|
||||||
// AppendReference adds a reference to the current ManifestBuilder
|
// AppendReference adds a reference to the current ManifestBuilder
|
||||||
func (mb *configManifestBuilder) AppendReference(d distribution.Describable) error {
|
func (mb *configManifestBuilder) AppendReference(d distribution.Describable) error {
|
||||||
// todo: verification here?
|
descriptor := d.Descriptor()
|
||||||
mb.descriptors = append(mb.descriptors, d.Descriptor())
|
|
||||||
|
if err := descriptor.Digest.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mb.descriptors = append(mb.descriptors, descriptor)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8
vendor/github.com/docker/distribution/manifest/schema1/config_builder_test.go
generated
vendored
8
vendor/github.com/docker/distribution/manifest/schema1/config_builder_test.go
generated
vendored
@@ -9,9 +9,9 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/libtrust"
|
"github.com/docker/libtrust"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockBlobService struct {
|
type mockBlobService struct {
|
||||||
@@ -197,10 +197,14 @@ func TestConfigBuilder(t *testing.T) {
|
|||||||
|
|
||||||
bs := &mockBlobService{descriptors: make(map[digest.Digest]distribution.Descriptor)}
|
bs := &mockBlobService{descriptors: make(map[digest.Digest]distribution.Descriptor)}
|
||||||
|
|
||||||
ref, err := reference.ParseNamed("testrepo:testtag")
|
ref, err := reference.WithName("testrepo")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not parse reference: %v", err)
|
t.Fatalf("could not parse reference: %v", err)
|
||||||
}
|
}
|
||||||
|
ref, err = reference.WithTag(ref, "testtag")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not add tag: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
builder := NewConfigManifestBuilder(bs, pk, ref, []byte(imgJSON))
|
builder := NewConfigManifestBuilder(bs, pk, ref, []byte(imgJSON))
|
||||||
|
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/manifest/schema1/manifest.go
generated
vendored
2
vendor/github.com/docker/distribution/manifest/schema1/manifest.go
generated
vendored
@@ -5,9 +5,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/manifest"
|
"github.com/docker/distribution/manifest"
|
||||||
"github.com/docker/libtrust"
|
"github.com/docker/libtrust"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/manifest/schema1/reference_builder.go
generated
vendored
2
vendor/github.com/docker/distribution/manifest/schema1/reference_builder.go
generated
vendored
@@ -6,10 +6,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/manifest"
|
"github.com/docker/distribution/manifest"
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/libtrust"
|
"github.com/docker/libtrust"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// referenceManifestBuilder is a type for constructing manifests from schema1
|
// referenceManifestBuilder is a type for constructing manifests from schema1
|
||||||
|
|||||||
4
vendor/github.com/docker/distribution/manifest/schema1/reference_builder_test.go
generated
vendored
4
vendor/github.com/docker/distribution/manifest/schema1/reference_builder_test.go
generated
vendored
@@ -4,10 +4,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/manifest"
|
"github.com/docker/distribution/manifest"
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/libtrust"
|
"github.com/docker/libtrust"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeSignedManifest(t *testing.T, pk libtrust.PrivateKey, refs []Reference) *SignedManifest {
|
func makeSignedManifest(t *testing.T, pk libtrust.PrivateKey, refs []Reference) *SignedManifest {
|
||||||
@@ -55,7 +55,7 @@ func TestReferenceBuilder(t *testing.T) {
|
|||||||
|
|
||||||
handCrafted := makeSignedManifest(t, pk, []Reference{r1, r2})
|
handCrafted := makeSignedManifest(t, pk, []Reference{r1, r2})
|
||||||
|
|
||||||
ref, err := reference.ParseNamed(handCrafted.Manifest.Name)
|
ref, err := reference.WithName(handCrafted.Manifest.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not parse reference: %v", err)
|
t.Fatalf("could not parse reference: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
28
vendor/github.com/docker/distribution/manifest/schema2/builder.go
generated
vendored
28
vendor/github.com/docker/distribution/manifest/schema2/builder.go
generated
vendored
@@ -3,7 +3,7 @@ package schema2
|
|||||||
import (
|
import (
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// builder is a type for constructing manifests.
|
// builder is a type for constructing manifests.
|
||||||
@@ -11,20 +11,24 @@ type builder struct {
|
|||||||
// bs is a BlobService used to publish the configuration blob.
|
// bs is a BlobService used to publish the configuration blob.
|
||||||
bs distribution.BlobService
|
bs distribution.BlobService
|
||||||
|
|
||||||
|
// configMediaType is media type used to describe configuration
|
||||||
|
configMediaType string
|
||||||
|
|
||||||
// configJSON references
|
// configJSON references
|
||||||
configJSON []byte
|
configJSON []byte
|
||||||
|
|
||||||
// layers is a list of layer descriptors that gets built by successive
|
// dependencies is a list of descriptors that gets built by successive
|
||||||
// calls to AppendReference.
|
// calls to AppendReference. In case of image configuration these are layers.
|
||||||
layers []distribution.Descriptor
|
dependencies []distribution.Descriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManifestBuilder is used to build new manifests for the current schema
|
// NewManifestBuilder is used to build new manifests for the current schema
|
||||||
// version. It takes a BlobService so it can publish the configuration blob
|
// version. It takes a BlobService so it can publish the configuration blob
|
||||||
// as part of the Build process.
|
// as part of the Build process.
|
||||||
func NewManifestBuilder(bs distribution.BlobService, configJSON []byte) distribution.ManifestBuilder {
|
func NewManifestBuilder(bs distribution.BlobService, configMediaType string, configJSON []byte) distribution.ManifestBuilder {
|
||||||
mb := &builder{
|
mb := &builder{
|
||||||
bs: bs,
|
bs: bs,
|
||||||
|
configMediaType: configMediaType,
|
||||||
configJSON: make([]byte, len(configJSON)),
|
configJSON: make([]byte, len(configJSON)),
|
||||||
}
|
}
|
||||||
copy(mb.configJSON, configJSON)
|
copy(mb.configJSON, configJSON)
|
||||||
@@ -36,9 +40,9 @@ func NewManifestBuilder(bs distribution.BlobService, configJSON []byte) distribu
|
|||||||
func (mb *builder) Build(ctx context.Context) (distribution.Manifest, error) {
|
func (mb *builder) Build(ctx context.Context) (distribution.Manifest, error) {
|
||||||
m := Manifest{
|
m := Manifest{
|
||||||
Versioned: SchemaVersion,
|
Versioned: SchemaVersion,
|
||||||
Layers: make([]distribution.Descriptor, len(mb.layers)),
|
Layers: make([]distribution.Descriptor, len(mb.dependencies)),
|
||||||
}
|
}
|
||||||
copy(m.Layers, mb.layers)
|
copy(m.Layers, mb.dependencies)
|
||||||
|
|
||||||
configDigest := digest.FromBytes(mb.configJSON)
|
configDigest := digest.FromBytes(mb.configJSON)
|
||||||
|
|
||||||
@@ -48,7 +52,7 @@ func (mb *builder) Build(ctx context.Context) (distribution.Manifest, error) {
|
|||||||
case nil:
|
case nil:
|
||||||
// Override MediaType, since Put always replaces the specified media
|
// Override MediaType, since Put always replaces the specified media
|
||||||
// type with application/octet-stream in the descriptor it returns.
|
// type with application/octet-stream in the descriptor it returns.
|
||||||
m.Config.MediaType = MediaTypeConfig
|
m.Config.MediaType = mb.configMediaType
|
||||||
return FromStruct(m)
|
return FromStruct(m)
|
||||||
case distribution.ErrBlobUnknown:
|
case distribution.ErrBlobUnknown:
|
||||||
// nop
|
// nop
|
||||||
@@ -57,10 +61,10 @@ func (mb *builder) Build(ctx context.Context) (distribution.Manifest, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add config to the blob store
|
// Add config to the blob store
|
||||||
m.Config, err = mb.bs.Put(ctx, MediaTypeConfig, mb.configJSON)
|
m.Config, err = mb.bs.Put(ctx, mb.configMediaType, mb.configJSON)
|
||||||
// Override MediaType, since Put always replaces the specified media
|
// Override MediaType, since Put always replaces the specified media
|
||||||
// type with application/octet-stream in the descriptor it returns.
|
// type with application/octet-stream in the descriptor it returns.
|
||||||
m.Config.MediaType = MediaTypeConfig
|
m.Config.MediaType = mb.configMediaType
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -70,11 +74,11 @@ func (mb *builder) Build(ctx context.Context) (distribution.Manifest, error) {
|
|||||||
|
|
||||||
// AppendReference adds a reference to the current ManifestBuilder.
|
// AppendReference adds a reference to the current ManifestBuilder.
|
||||||
func (mb *builder) AppendReference(d distribution.Describable) error {
|
func (mb *builder) AppendReference(d distribution.Describable) error {
|
||||||
mb.layers = append(mb.layers, d.Descriptor())
|
mb.dependencies = append(mb.dependencies, d.Descriptor())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// References returns the current references added to this builder.
|
// References returns the current references added to this builder.
|
||||||
func (mb *builder) References() []distribution.Descriptor {
|
func (mb *builder) References() []distribution.Descriptor {
|
||||||
return mb.layers
|
return mb.dependencies
|
||||||
}
|
}
|
||||||
|
|||||||
6
vendor/github.com/docker/distribution/manifest/schema2/builder_test.go
generated
vendored
6
vendor/github.com/docker/distribution/manifest/schema2/builder_test.go
generated
vendored
@@ -6,7 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockBlobService struct {
|
type mockBlobService struct {
|
||||||
@@ -166,7 +166,7 @@ func TestBuilder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bs := &mockBlobService{descriptors: make(map[digest.Digest]distribution.Descriptor)}
|
bs := &mockBlobService{descriptors: make(map[digest.Digest]distribution.Descriptor)}
|
||||||
builder := NewManifestBuilder(bs, imgJSON)
|
builder := NewManifestBuilder(bs, MediaTypeImageConfig, imgJSON)
|
||||||
|
|
||||||
for _, d := range descriptors {
|
for _, d := range descriptors {
|
||||||
if err := builder.AppendReference(d); err != nil {
|
if err := builder.AppendReference(d); err != nil {
|
||||||
@@ -195,7 +195,7 @@ func TestBuilder(t *testing.T) {
|
|||||||
if target.Digest != configDigest {
|
if target.Digest != configDigest {
|
||||||
t.Fatalf("unexpected digest in target: %s", target.Digest.String())
|
t.Fatalf("unexpected digest in target: %s", target.Digest.String())
|
||||||
}
|
}
|
||||||
if target.MediaType != MediaTypeConfig {
|
if target.MediaType != MediaTypeImageConfig {
|
||||||
t.Fatalf("unexpected media type in target: %s", target.MediaType)
|
t.Fatalf("unexpected media type in target: %s", target.MediaType)
|
||||||
}
|
}
|
||||||
if target.Size != 3153 {
|
if target.Size != 3153 {
|
||||||
|
|||||||
10
vendor/github.com/docker/distribution/manifest/schema2/manifest.go
generated
vendored
10
vendor/github.com/docker/distribution/manifest/schema2/manifest.go
generated
vendored
@@ -6,16 +6,16 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/manifest"
|
"github.com/docker/distribution/manifest"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// MediaTypeManifest specifies the mediaType for the current version.
|
// MediaTypeManifest specifies the mediaType for the current version.
|
||||||
MediaTypeManifest = "application/vnd.docker.distribution.manifest.v2+json"
|
MediaTypeManifest = "application/vnd.docker.distribution.manifest.v2+json"
|
||||||
|
|
||||||
// MediaTypeConfig specifies the mediaType for the image configuration.
|
// MediaTypeImageConfig specifies the mediaType for the image configuration.
|
||||||
MediaTypeConfig = "application/vnd.docker.container.image.v1+json"
|
MediaTypeImageConfig = "application/vnd.docker.container.image.v1+json"
|
||||||
|
|
||||||
// MediaTypePluginConfig specifies the mediaType for plugin configuration.
|
// MediaTypePluginConfig specifies the mediaType for plugin configuration.
|
||||||
MediaTypePluginConfig = "application/vnd.docker.plugin.v1+json"
|
MediaTypePluginConfig = "application/vnd.docker.plugin.v1+json"
|
||||||
@@ -27,6 +27,10 @@ const (
|
|||||||
// MediaTypeForeignLayer is the mediaType used for layers that must be
|
// MediaTypeForeignLayer is the mediaType used for layers that must be
|
||||||
// downloaded from foreign URLs.
|
// downloaded from foreign URLs.
|
||||||
MediaTypeForeignLayer = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip"
|
MediaTypeForeignLayer = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip"
|
||||||
|
|
||||||
|
// MediaTypeUncompressedLayer is the mediaType used for layers which
|
||||||
|
// are not compressed.
|
||||||
|
MediaTypeUncompressedLayer = "application/vnd.docker.image.rootfs.diff.tar"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
4
vendor/github.com/docker/distribution/manifest/schema2/manifest_test.go
generated
vendored
4
vendor/github.com/docker/distribution/manifest/schema2/manifest_test.go
generated
vendored
@@ -32,7 +32,7 @@ func TestManifest(t *testing.T) {
|
|||||||
Config: distribution.Descriptor{
|
Config: distribution.Descriptor{
|
||||||
Digest: "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b",
|
Digest: "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b",
|
||||||
Size: 985,
|
Size: 985,
|
||||||
MediaType: MediaTypeConfig,
|
MediaType: MediaTypeImageConfig,
|
||||||
},
|
},
|
||||||
Layers: []distribution.Descriptor{
|
Layers: []distribution.Descriptor{
|
||||||
{
|
{
|
||||||
@@ -82,7 +82,7 @@ func TestManifest(t *testing.T) {
|
|||||||
if target.Digest != "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b" {
|
if target.Digest != "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b" {
|
||||||
t.Fatalf("unexpected digest in target: %s", target.Digest.String())
|
t.Fatalf("unexpected digest in target: %s", target.Digest.String())
|
||||||
}
|
}
|
||||||
if target.MediaType != MediaTypeConfig {
|
if target.MediaType != MediaTypeImageConfig {
|
||||||
t.Fatalf("unexpected media type in target: %s", target.MediaType)
|
t.Fatalf("unexpected media type in target: %s", target.MediaType)
|
||||||
}
|
}
|
||||||
if target.Size != 985 {
|
if target.Size != 985 {
|
||||||
|
|||||||
20
vendor/github.com/docker/distribution/manifests.go
generated
vendored
20
vendor/github.com/docker/distribution/manifests.go
generated
vendored
@@ -5,7 +5,7 @@ import (
|
|||||||
"mime"
|
"mime"
|
||||||
|
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Manifest represents a registry object specifying a set of
|
// Manifest represents a registry object specifying a set of
|
||||||
@@ -23,7 +23,7 @@ type Manifest interface {
|
|||||||
|
|
||||||
// Payload provides the serialized format of the manifest, in addition to
|
// Payload provides the serialized format of the manifest, in addition to
|
||||||
// the media type.
|
// the media type.
|
||||||
Payload() (mediatype string, payload []byte, err error)
|
Payload() (mediaType string, payload []byte, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ManifestBuilder creates a manifest allowing one to include dependencies.
|
// ManifestBuilder creates a manifest allowing one to include dependencies.
|
||||||
@@ -94,20 +94,20 @@ var mappings = make(map[string]UnmarshalFunc, 0)
|
|||||||
func UnmarshalManifest(ctHeader string, p []byte) (Manifest, Descriptor, error) {
|
func UnmarshalManifest(ctHeader string, p []byte) (Manifest, Descriptor, error) {
|
||||||
// Need to look up by the actual media type, not the raw contents of
|
// Need to look up by the actual media type, not the raw contents of
|
||||||
// the header. Strip semicolons and anything following them.
|
// the header. Strip semicolons and anything following them.
|
||||||
var mediatype string
|
var mediaType string
|
||||||
if ctHeader != "" {
|
if ctHeader != "" {
|
||||||
var err error
|
var err error
|
||||||
mediatype, _, err = mime.ParseMediaType(ctHeader)
|
mediaType, _, err = mime.ParseMediaType(ctHeader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Descriptor{}, err
|
return nil, Descriptor{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unmarshalFunc, ok := mappings[mediatype]
|
unmarshalFunc, ok := mappings[mediaType]
|
||||||
if !ok {
|
if !ok {
|
||||||
unmarshalFunc, ok = mappings[""]
|
unmarshalFunc, ok = mappings[""]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, Descriptor{}, fmt.Errorf("unsupported manifest mediatype and no default available: %s", mediatype)
|
return nil, Descriptor{}, fmt.Errorf("unsupported manifest media type and no default available: %s", mediaType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,10 +116,10 @@ func UnmarshalManifest(ctHeader string, p []byte) (Manifest, Descriptor, error)
|
|||||||
|
|
||||||
// RegisterManifestSchema registers an UnmarshalFunc for a given schema type. This
|
// RegisterManifestSchema registers an UnmarshalFunc for a given schema type. This
|
||||||
// should be called from specific
|
// should be called from specific
|
||||||
func RegisterManifestSchema(mediatype string, u UnmarshalFunc) error {
|
func RegisterManifestSchema(mediaType string, u UnmarshalFunc) error {
|
||||||
if _, ok := mappings[mediatype]; ok {
|
if _, ok := mappings[mediaType]; ok {
|
||||||
return fmt.Errorf("manifest mediatype registration would overwrite existing: %s", mediatype)
|
return fmt.Errorf("manifest media type registration would overwrite existing: %s", mediaType)
|
||||||
}
|
}
|
||||||
mappings[mediatype] = u
|
mappings[mediaType] = u
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/notifications/bridge.go
generated
vendored
2
vendor/github.com/docker/distribution/notifications/bridge.go
generated
vendored
@@ -6,9 +6,9 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/uuid"
|
"github.com/docker/distribution/uuid"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
type bridge struct {
|
type bridge struct {
|
||||||
|
|||||||
14
vendor/github.com/docker/distribution/notifications/bridge_test.go
generated
vendored
14
vendor/github.com/docker/distribution/notifications/bridge_test.go
generated
vendored
@@ -4,12 +4,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/api/v2"
|
"github.com/docker/distribution/registry/api/v2"
|
||||||
"github.com/docker/distribution/uuid"
|
"github.com/docker/distribution/uuid"
|
||||||
"github.com/docker/libtrust"
|
"github.com/docker/libtrust"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -43,7 +43,7 @@ func TestEventBridgeManifestPulled(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
repoRef, _ := reference.ParseNamed(repo)
|
repoRef, _ := reference.WithName(repo)
|
||||||
if err := l.ManifestPulled(repoRef, sm); err != nil {
|
if err := l.ManifestPulled(repoRef, sm); err != nil {
|
||||||
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ func TestEventBridgeManifestPushed(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
repoRef, _ := reference.ParseNamed(repo)
|
repoRef, _ := reference.WithName(repo)
|
||||||
if err := l.ManifestPushed(repoRef, sm); err != nil {
|
if err := l.ManifestPushed(repoRef, sm); err != nil {
|
||||||
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ func TestEventBridgeManifestPushedWithTag(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
repoRef, _ := reference.ParseNamed(repo)
|
repoRef, _ := reference.WithName(repo)
|
||||||
if err := l.ManifestPushed(repoRef, sm, distribution.WithTag(m.Tag)); err != nil {
|
if err := l.ManifestPushed(repoRef, sm, distribution.WithTag(m.Tag)); err != nil {
|
||||||
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ func TestEventBridgeManifestPulledWithTag(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
repoRef, _ := reference.ParseNamed(repo)
|
repoRef, _ := reference.WithName(repo)
|
||||||
if err := l.ManifestPulled(repoRef, sm, distribution.WithTag(m.Tag)); err != nil {
|
if err := l.ManifestPulled(repoRef, sm, distribution.WithTag(m.Tag)); err != nil {
|
||||||
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
||||||
}
|
}
|
||||||
@@ -100,7 +100,7 @@ func TestEventBridgeManifestDeleted(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
repoRef, _ := reference.ParseNamed(repo)
|
repoRef, _ := reference.WithName(repo)
|
||||||
if err := l.ManifestDeleted(repoRef, dgst); err != nil {
|
if err := l.ManifestDeleted(repoRef, dgst); err != nil {
|
||||||
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ func checkCommonManifest(t *testing.T, action string, events ...Event) {
|
|||||||
t.Fatalf("unexpected event action: %q != %q", event.Action, action)
|
t.Fatalf("unexpected event action: %q != %q", event.Action, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
repoRef, _ := reference.ParseNamed(repo)
|
repoRef, _ := reference.WithName(repo)
|
||||||
ref, _ := reference.WithDigest(repoRef, dgst)
|
ref, _ := reference.WithDigest(repoRef, dgst)
|
||||||
u, err := ub.BuildManifestURL(ref)
|
u, err := ub.BuildManifestURL(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/notifications/endpoint.go
generated
vendored
2
vendor/github.com/docker/distribution/notifications/endpoint.go
generated
vendored
@@ -13,7 +13,7 @@ type EndpointConfig struct {
|
|||||||
Threshold int
|
Threshold int
|
||||||
Backoff time.Duration
|
Backoff time.Duration
|
||||||
IgnoredMediaTypes []string
|
IgnoredMediaTypes []string
|
||||||
Transport *http.Transport
|
Transport *http.Transport `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaults set any zero-valued fields to a reasonable default.
|
// defaults set any zero-valued fields to a reasonable default.
|
||||||
|
|||||||
4
vendor/github.com/docker/distribution/notifications/event.go
generated
vendored
4
vendor/github.com/docker/distribution/notifications/event.go
generated
vendored
@@ -77,7 +77,7 @@ type Event struct {
|
|||||||
Request RequestRecord `json:"request,omitempty"`
|
Request RequestRecord `json:"request,omitempty"`
|
||||||
|
|
||||||
// Actor specifies the agent that initiated the event. For most
|
// Actor specifies the agent that initiated the event. For most
|
||||||
// situations, this could be from the authorizaton context of the request.
|
// situations, this could be from the authorization context of the request.
|
||||||
Actor ActorRecord `json:"actor,omitempty"`
|
Actor ActorRecord `json:"actor,omitempty"`
|
||||||
|
|
||||||
// Source identifies the registry node that generated the event. Put
|
// Source identifies the registry node that generated the event. Put
|
||||||
@@ -87,7 +87,7 @@ type Event struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ActorRecord specifies the agent that initiated the event. For most
|
// ActorRecord specifies the agent that initiated the event. For most
|
||||||
// situations, this could be from the authorizaton context of the request.
|
// situations, this could be from the authorization context of the request.
|
||||||
// Data in this record can refer to both the initiating client and the
|
// Data in this record can refer to both the initiating client and the
|
||||||
// generating request.
|
// generating request.
|
||||||
type ActorRecord struct {
|
type ActorRecord struct {
|
||||||
|
|||||||
20
vendor/github.com/docker/distribution/notifications/http_test.go
generated
vendored
20
vendor/github.com/docker/distribution/notifications/http_test.go
generated
vendored
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"mime"
|
"mime"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -94,6 +95,21 @@ func TestHTTPSink(t *testing.T) {
|
|||||||
var expectedMetrics EndpointMetrics
|
var expectedMetrics EndpointMetrics
|
||||||
expectedMetrics.Statuses = make(map[string]int)
|
expectedMetrics.Statuses = make(map[string]int)
|
||||||
|
|
||||||
|
closeL, err := net.Listen("tcp", "localhost:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error creating listener: %v", err)
|
||||||
|
}
|
||||||
|
defer closeL.Close()
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
c, err := closeL.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
events []Event // events to send
|
events []Event // events to send
|
||||||
url string
|
url string
|
||||||
@@ -121,8 +137,8 @@ func TestHTTPSink(t *testing.T) {
|
|||||||
failure: true,
|
failure: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Case where connection never goes through.
|
// Case where connection is immediately closed
|
||||||
url: "http://shoudlntresolve/",
|
url: closeL.Addr().String(),
|
||||||
failure: true,
|
failure: true,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/notifications/listener.go
generated
vendored
2
vendor/github.com/docker/distribution/notifications/listener.go
generated
vendored
@@ -5,8 +5,8 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ManifestListener describes a set of methods for listening to events related to manifests.
|
// ManifestListener describes a set of methods for listening to events related to manifests.
|
||||||
|
|||||||
4
vendor/github.com/docker/distribution/notifications/listener_test.go
generated
vendored
4
vendor/github.com/docker/distribution/notifications/listener_test.go
generated
vendored
@@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/manifest"
|
"github.com/docker/distribution/manifest"
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
@@ -16,6 +15,7 @@ import (
|
|||||||
"github.com/docker/distribution/registry/storage/driver/inmemory"
|
"github.com/docker/distribution/registry/storage/driver/inmemory"
|
||||||
"github.com/docker/distribution/testutil"
|
"github.com/docker/distribution/testutil"
|
||||||
"github.com/docker/libtrust"
|
"github.com/docker/libtrust"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestListener(t *testing.T) {
|
func TestListener(t *testing.T) {
|
||||||
@@ -33,7 +33,7 @@ func TestListener(t *testing.T) {
|
|||||||
ops: make(map[string]int),
|
ops: make(map[string]int),
|
||||||
}
|
}
|
||||||
|
|
||||||
repoRef, _ := reference.ParseNamed("foo/bar")
|
repoRef, _ := reference.WithName("foo/bar")
|
||||||
repository, err := registry.Repository(ctx, repoRef)
|
repository, err := registry.Repository(ctx, repoRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error getting repo: %v", err)
|
t.Fatalf("unexpected error getting repo: %v", err)
|
||||||
|
|||||||
28
vendor/github.com/docker/distribution/notifications/metrics_test.go
generated
vendored
Normal file
28
vendor/github.com/docker/distribution/notifications/metrics_test.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package notifications
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"expvar"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMetricsExpvar(t *testing.T) {
|
||||||
|
endpointsVar := expvar.Get("registry").(*expvar.Map).Get("notifications").(*expvar.Map).Get("endpoints")
|
||||||
|
|
||||||
|
var v interface{}
|
||||||
|
if err := json.Unmarshal([]byte(endpointsVar.String()), &v); err != nil {
|
||||||
|
t.Fatalf("unexpected error unmarshaling endpoints: %v", err)
|
||||||
|
}
|
||||||
|
if v != nil {
|
||||||
|
t.Fatalf("expected nil, got %#v", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
NewEndpoint("x", "y", EndpointConfig{})
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(endpointsVar.String()), &v); err != nil {
|
||||||
|
t.Fatalf("unexpected error unmarshaling endpoints: %v", err)
|
||||||
|
}
|
||||||
|
if slice, ok := v.([]interface{}); !ok || len(slice) != 1 {
|
||||||
|
t.Logf("expected one-element []interface{}, got %#v", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
42
vendor/github.com/docker/distribution/reference/helpers.go
generated
vendored
Normal file
42
vendor/github.com/docker/distribution/reference/helpers.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package reference
|
||||||
|
|
||||||
|
import "path"
|
||||||
|
|
||||||
|
// IsNameOnly returns true if reference only contains a repo name.
|
||||||
|
func IsNameOnly(ref Named) bool {
|
||||||
|
if _, ok := ref.(NamedTagged); ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if _, ok := ref.(Canonical); ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// FamiliarName returns the familiar name string
|
||||||
|
// for the given named, familiarizing if needed.
|
||||||
|
func FamiliarName(ref Named) string {
|
||||||
|
if nn, ok := ref.(normalizedNamed); ok {
|
||||||
|
return nn.Familiar().Name()
|
||||||
|
}
|
||||||
|
return ref.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FamiliarString returns the familiar string representation
|
||||||
|
// for the given reference, familiarizing if needed.
|
||||||
|
func FamiliarString(ref Reference) string {
|
||||||
|
if nn, ok := ref.(normalizedNamed); ok {
|
||||||
|
return nn.Familiar().String()
|
||||||
|
}
|
||||||
|
return ref.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FamiliarMatch reports whether ref matches the specified pattern.
|
||||||
|
// See https://godoc.org/path#Match for supported patterns.
|
||||||
|
func FamiliarMatch(pattern string, ref Reference) (bool, error) {
|
||||||
|
matched, err := path.Match(pattern, FamiliarString(ref))
|
||||||
|
if namedRef, isNamed := ref.(Named); isNamed && !matched {
|
||||||
|
matched, _ = path.Match(pattern, FamiliarName(namedRef))
|
||||||
|
}
|
||||||
|
return matched, err
|
||||||
|
}
|
||||||
170
vendor/github.com/docker/distribution/reference/normalize.go
generated
vendored
Normal file
170
vendor/github.com/docker/distribution/reference/normalize.go
generated
vendored
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
package reference
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/digestset"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
legacyDefaultDomain = "index.docker.io"
|
||||||
|
defaultDomain = "docker.io"
|
||||||
|
officialRepoName = "library"
|
||||||
|
defaultTag = "latest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// normalizedNamed represents a name which has been
|
||||||
|
// normalized and has a familiar form. A familiar name
|
||||||
|
// is what is used in Docker UI. An example normalized
|
||||||
|
// name is "docker.io/library/ubuntu" and corresponding
|
||||||
|
// familiar name of "ubuntu".
|
||||||
|
type normalizedNamed interface {
|
||||||
|
Named
|
||||||
|
Familiar() Named
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseNormalizedNamed parses a string into a named reference
|
||||||
|
// transforming a familiar name from Docker UI to a fully
|
||||||
|
// qualified reference. If the value may be an identifier
|
||||||
|
// use ParseAnyReference.
|
||||||
|
func ParseNormalizedNamed(s string) (Named, error) {
|
||||||
|
if ok := anchoredIdentifierRegexp.MatchString(s); ok {
|
||||||
|
return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s)
|
||||||
|
}
|
||||||
|
domain, remainder := splitDockerDomain(s)
|
||||||
|
var remoteName string
|
||||||
|
if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 {
|
||||||
|
remoteName = remainder[:tagSep]
|
||||||
|
} else {
|
||||||
|
remoteName = remainder
|
||||||
|
}
|
||||||
|
if strings.ToLower(remoteName) != remoteName {
|
||||||
|
return nil, errors.New("invalid reference format: repository name must be lowercase")
|
||||||
|
}
|
||||||
|
|
||||||
|
ref, err := Parse(domain + "/" + remainder)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
named, isNamed := ref.(Named)
|
||||||
|
if !isNamed {
|
||||||
|
return nil, fmt.Errorf("reference %s has no name", ref.String())
|
||||||
|
}
|
||||||
|
return named, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitDockerDomain splits a repository name to domain and remotename string.
|
||||||
|
// If no valid domain is found, the default domain is used. Repository name
|
||||||
|
// needs to be already validated before.
|
||||||
|
func splitDockerDomain(name string) (domain, remainder string) {
|
||||||
|
i := strings.IndexRune(name, '/')
|
||||||
|
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") {
|
||||||
|
domain, remainder = defaultDomain, name
|
||||||
|
} else {
|
||||||
|
domain, remainder = name[:i], name[i+1:]
|
||||||
|
}
|
||||||
|
if domain == legacyDefaultDomain {
|
||||||
|
domain = defaultDomain
|
||||||
|
}
|
||||||
|
if domain == defaultDomain && !strings.ContainsRune(remainder, '/') {
|
||||||
|
remainder = officialRepoName + "/" + remainder
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// familiarizeName returns a shortened version of the name familiar
|
||||||
|
// to to the Docker UI. Familiar names have the default domain
|
||||||
|
// "docker.io" and "library/" repository prefix removed.
|
||||||
|
// For example, "docker.io/library/redis" will have the familiar
|
||||||
|
// name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp".
|
||||||
|
// Returns a familiarized named only reference.
|
||||||
|
func familiarizeName(named namedRepository) repository {
|
||||||
|
repo := repository{
|
||||||
|
domain: named.Domain(),
|
||||||
|
path: named.Path(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if repo.domain == defaultDomain {
|
||||||
|
repo.domain = ""
|
||||||
|
// Handle official repositories which have the pattern "library/<official repo name>"
|
||||||
|
if split := strings.Split(repo.path, "/"); len(split) == 2 && split[0] == officialRepoName {
|
||||||
|
repo.path = split[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return repo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r reference) Familiar() Named {
|
||||||
|
return reference{
|
||||||
|
namedRepository: familiarizeName(r.namedRepository),
|
||||||
|
tag: r.tag,
|
||||||
|
digest: r.digest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r repository) Familiar() Named {
|
||||||
|
return familiarizeName(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t taggedReference) Familiar() Named {
|
||||||
|
return taggedReference{
|
||||||
|
namedRepository: familiarizeName(t.namedRepository),
|
||||||
|
tag: t.tag,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c canonicalReference) Familiar() Named {
|
||||||
|
return canonicalReference{
|
||||||
|
namedRepository: familiarizeName(c.namedRepository),
|
||||||
|
digest: c.digest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TagNameOnly adds the default tag "latest" to a reference if it only has
|
||||||
|
// a repo name.
|
||||||
|
func TagNameOnly(ref Named) Named {
|
||||||
|
if IsNameOnly(ref) {
|
||||||
|
namedTagged, err := WithTag(ref, defaultTag)
|
||||||
|
if err != nil {
|
||||||
|
// Default tag must be valid, to create a NamedTagged
|
||||||
|
// type with non-validated input the WithTag function
|
||||||
|
// should be used instead
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return namedTagged
|
||||||
|
}
|
||||||
|
return ref
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseAnyReference parses a reference string as a possible identifier,
|
||||||
|
// full digest, or familiar name.
|
||||||
|
func ParseAnyReference(ref string) (Reference, error) {
|
||||||
|
if ok := anchoredIdentifierRegexp.MatchString(ref); ok {
|
||||||
|
return digestReference("sha256:" + ref), nil
|
||||||
|
}
|
||||||
|
if dgst, err := digest.Parse(ref); err == nil {
|
||||||
|
return digestReference(dgst), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseNormalizedNamed(ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseAnyReferenceWithSet parses a reference string as a possible short
|
||||||
|
// identifier to be matched in a digest set, a full digest, or familiar name.
|
||||||
|
func ParseAnyReferenceWithSet(ref string, ds *digestset.Set) (Reference, error) {
|
||||||
|
if ok := anchoredShortIdentifierRegexp.MatchString(ref); ok {
|
||||||
|
dgst, err := ds.Lookup(ref)
|
||||||
|
if err == nil {
|
||||||
|
return digestReference(dgst), nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if dgst, err := digest.Parse(ref); err == nil {
|
||||||
|
return digestReference(dgst), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseNormalizedNamed(ref)
|
||||||
|
}
|
||||||
625
vendor/github.com/docker/distribution/reference/normalize_test.go
generated
vendored
Normal file
625
vendor/github.com/docker/distribution/reference/normalize_test.go
generated
vendored
Normal file
@@ -0,0 +1,625 @@
|
|||||||
|
package reference
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/digestset"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidateReferenceName(t *testing.T) {
|
||||||
|
validRepoNames := []string{
|
||||||
|
"docker/docker",
|
||||||
|
"library/debian",
|
||||||
|
"debian",
|
||||||
|
"docker.io/docker/docker",
|
||||||
|
"docker.io/library/debian",
|
||||||
|
"docker.io/debian",
|
||||||
|
"index.docker.io/docker/docker",
|
||||||
|
"index.docker.io/library/debian",
|
||||||
|
"index.docker.io/debian",
|
||||||
|
"127.0.0.1:5000/docker/docker",
|
||||||
|
"127.0.0.1:5000/library/debian",
|
||||||
|
"127.0.0.1:5000/debian",
|
||||||
|
"thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev",
|
||||||
|
|
||||||
|
// This test case was moved from invalid to valid since it is valid input
|
||||||
|
// when specified with a hostname, it removes the ambiguity from about
|
||||||
|
// whether the value is an identifier or repository name
|
||||||
|
"docker.io/1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
|
||||||
|
}
|
||||||
|
invalidRepoNames := []string{
|
||||||
|
"https://github.com/docker/docker",
|
||||||
|
"docker/Docker",
|
||||||
|
"-docker",
|
||||||
|
"-docker/docker",
|
||||||
|
"-docker.io/docker/docker",
|
||||||
|
"docker///docker",
|
||||||
|
"docker.io/docker/Docker",
|
||||||
|
"docker.io/docker///docker",
|
||||||
|
"1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range invalidRepoNames {
|
||||||
|
_, err := ParseNormalizedNamed(name)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Expected invalid repo name for %q", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range validRepoNames {
|
||||||
|
_, err := ParseNormalizedNamed(name)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error parsing repo name %s, got: %q", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateRemoteName(t *testing.T) {
|
||||||
|
validRepositoryNames := []string{
|
||||||
|
// Sanity check.
|
||||||
|
"docker/docker",
|
||||||
|
|
||||||
|
// Allow 64-character non-hexadecimal names (hexadecimal names are forbidden).
|
||||||
|
"thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev",
|
||||||
|
|
||||||
|
// Allow embedded hyphens.
|
||||||
|
"docker-rules/docker",
|
||||||
|
|
||||||
|
// Allow multiple hyphens as well.
|
||||||
|
"docker---rules/docker",
|
||||||
|
|
||||||
|
//Username doc and image name docker being tested.
|
||||||
|
"doc/docker",
|
||||||
|
|
||||||
|
// single character names are now allowed.
|
||||||
|
"d/docker",
|
||||||
|
"jess/t",
|
||||||
|
|
||||||
|
// Consecutive underscores.
|
||||||
|
"dock__er/docker",
|
||||||
|
}
|
||||||
|
for _, repositoryName := range validRepositoryNames {
|
||||||
|
_, err := ParseNormalizedNamed(repositoryName)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Repository name should be valid: %v. Error: %v", repositoryName, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidRepositoryNames := []string{
|
||||||
|
// Disallow capital letters.
|
||||||
|
"docker/Docker",
|
||||||
|
|
||||||
|
// Only allow one slash.
|
||||||
|
"docker///docker",
|
||||||
|
|
||||||
|
// Disallow 64-character hexadecimal.
|
||||||
|
"1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
|
||||||
|
|
||||||
|
// Disallow leading and trailing hyphens in namespace.
|
||||||
|
"-docker/docker",
|
||||||
|
"docker-/docker",
|
||||||
|
"-docker-/docker",
|
||||||
|
|
||||||
|
// Don't allow underscores everywhere (as opposed to hyphens).
|
||||||
|
"____/____",
|
||||||
|
|
||||||
|
"_docker/_docker",
|
||||||
|
|
||||||
|
// Disallow consecutive periods.
|
||||||
|
"dock..er/docker",
|
||||||
|
"dock_.er/docker",
|
||||||
|
"dock-.er/docker",
|
||||||
|
|
||||||
|
// No repository.
|
||||||
|
"docker/",
|
||||||
|
|
||||||
|
//namespace too long
|
||||||
|
"this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255/docker",
|
||||||
|
}
|
||||||
|
for _, repositoryName := range invalidRepositoryNames {
|
||||||
|
if _, err := ParseNormalizedNamed(repositoryName); err == nil {
|
||||||
|
t.Errorf("Repository name should be invalid: %v", repositoryName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseRepositoryInfo(t *testing.T) {
|
||||||
|
type tcase struct {
|
||||||
|
RemoteName, FamiliarName, FullName, AmbiguousName, Domain string
|
||||||
|
}
|
||||||
|
|
||||||
|
tcases := []tcase{
|
||||||
|
{
|
||||||
|
RemoteName: "fooo/bar",
|
||||||
|
FamiliarName: "fooo/bar",
|
||||||
|
FullName: "docker.io/fooo/bar",
|
||||||
|
AmbiguousName: "index.docker.io/fooo/bar",
|
||||||
|
Domain: "docker.io",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RemoteName: "library/ubuntu",
|
||||||
|
FamiliarName: "ubuntu",
|
||||||
|
FullName: "docker.io/library/ubuntu",
|
||||||
|
AmbiguousName: "library/ubuntu",
|
||||||
|
Domain: "docker.io",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RemoteName: "nonlibrary/ubuntu",
|
||||||
|
FamiliarName: "nonlibrary/ubuntu",
|
||||||
|
FullName: "docker.io/nonlibrary/ubuntu",
|
||||||
|
AmbiguousName: "",
|
||||||
|
Domain: "docker.io",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RemoteName: "other/library",
|
||||||
|
FamiliarName: "other/library",
|
||||||
|
FullName: "docker.io/other/library",
|
||||||
|
AmbiguousName: "",
|
||||||
|
Domain: "docker.io",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RemoteName: "private/moonbase",
|
||||||
|
FamiliarName: "127.0.0.1:8000/private/moonbase",
|
||||||
|
FullName: "127.0.0.1:8000/private/moonbase",
|
||||||
|
AmbiguousName: "",
|
||||||
|
Domain: "127.0.0.1:8000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RemoteName: "privatebase",
|
||||||
|
FamiliarName: "127.0.0.1:8000/privatebase",
|
||||||
|
FullName: "127.0.0.1:8000/privatebase",
|
||||||
|
AmbiguousName: "",
|
||||||
|
Domain: "127.0.0.1:8000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RemoteName: "private/moonbase",
|
||||||
|
FamiliarName: "example.com/private/moonbase",
|
||||||
|
FullName: "example.com/private/moonbase",
|
||||||
|
AmbiguousName: "",
|
||||||
|
Domain: "example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RemoteName: "privatebase",
|
||||||
|
FamiliarName: "example.com/privatebase",
|
||||||
|
FullName: "example.com/privatebase",
|
||||||
|
AmbiguousName: "",
|
||||||
|
Domain: "example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RemoteName: "private/moonbase",
|
||||||
|
FamiliarName: "example.com:8000/private/moonbase",
|
||||||
|
FullName: "example.com:8000/private/moonbase",
|
||||||
|
AmbiguousName: "",
|
||||||
|
Domain: "example.com:8000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RemoteName: "privatebasee",
|
||||||
|
FamiliarName: "example.com:8000/privatebasee",
|
||||||
|
FullName: "example.com:8000/privatebasee",
|
||||||
|
AmbiguousName: "",
|
||||||
|
Domain: "example.com:8000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RemoteName: "library/ubuntu-12.04-base",
|
||||||
|
FamiliarName: "ubuntu-12.04-base",
|
||||||
|
FullName: "docker.io/library/ubuntu-12.04-base",
|
||||||
|
AmbiguousName: "index.docker.io/library/ubuntu-12.04-base",
|
||||||
|
Domain: "docker.io",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RemoteName: "library/foo",
|
||||||
|
FamiliarName: "foo",
|
||||||
|
FullName: "docker.io/library/foo",
|
||||||
|
AmbiguousName: "docker.io/foo",
|
||||||
|
Domain: "docker.io",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RemoteName: "library/foo/bar",
|
||||||
|
FamiliarName: "library/foo/bar",
|
||||||
|
FullName: "docker.io/library/foo/bar",
|
||||||
|
AmbiguousName: "",
|
||||||
|
Domain: "docker.io",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RemoteName: "store/foo/bar",
|
||||||
|
FamiliarName: "store/foo/bar",
|
||||||
|
FullName: "docker.io/store/foo/bar",
|
||||||
|
AmbiguousName: "",
|
||||||
|
Domain: "docker.io",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tcase := range tcases {
|
||||||
|
refStrings := []string{tcase.FamiliarName, tcase.FullName}
|
||||||
|
if tcase.AmbiguousName != "" {
|
||||||
|
refStrings = append(refStrings, tcase.AmbiguousName)
|
||||||
|
}
|
||||||
|
|
||||||
|
var refs []Named
|
||||||
|
for _, r := range refStrings {
|
||||||
|
named, err := ParseNormalizedNamed(r)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
refs = append(refs, named)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range refs {
|
||||||
|
if expected, actual := tcase.FamiliarName, FamiliarName(r); expected != actual {
|
||||||
|
t.Fatalf("Invalid normalized reference for %q. Expected %q, got %q", r, expected, actual)
|
||||||
|
}
|
||||||
|
if expected, actual := tcase.FullName, r.String(); expected != actual {
|
||||||
|
t.Fatalf("Invalid canonical reference for %q. Expected %q, got %q", r, expected, actual)
|
||||||
|
}
|
||||||
|
if expected, actual := tcase.Domain, Domain(r); expected != actual {
|
||||||
|
t.Fatalf("Invalid domain for %q. Expected %q, got %q", r, expected, actual)
|
||||||
|
}
|
||||||
|
if expected, actual := tcase.RemoteName, Path(r); expected != actual {
|
||||||
|
t.Fatalf("Invalid remoteName for %q. Expected %q, got %q", r, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseReferenceWithTagAndDigest(t *testing.T) {
|
||||||
|
shortRef := "busybox:latest@sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa"
|
||||||
|
ref, err := ParseNormalizedNamed(shortRef)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if expected, actual := "docker.io/library/"+shortRef, ref.String(); actual != expected {
|
||||||
|
t.Fatalf("Invalid parsed reference for %q: expected %q, got %q", ref, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, isTagged := ref.(NamedTagged); !isTagged {
|
||||||
|
t.Fatalf("Reference from %q should support tag", ref)
|
||||||
|
}
|
||||||
|
if _, isCanonical := ref.(Canonical); !isCanonical {
|
||||||
|
t.Fatalf("Reference from %q should support digest", ref)
|
||||||
|
}
|
||||||
|
if expected, actual := shortRef, FamiliarString(ref); actual != expected {
|
||||||
|
t.Fatalf("Invalid parsed reference for %q: expected %q, got %q", ref, expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidReferenceComponents(t *testing.T) {
|
||||||
|
if _, err := ParseNormalizedNamed("-foo"); err == nil {
|
||||||
|
t.Fatal("Expected WithName to detect invalid name")
|
||||||
|
}
|
||||||
|
ref, err := ParseNormalizedNamed("busybox")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, err := WithTag(ref, "-foo"); err == nil {
|
||||||
|
t.Fatal("Expected WithName to detect invalid tag")
|
||||||
|
}
|
||||||
|
if _, err := WithDigest(ref, digest.Digest("foo")); err == nil {
|
||||||
|
t.Fatal("Expected WithDigest to detect invalid digest")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func equalReference(r1, r2 Reference) bool {
|
||||||
|
switch v1 := r1.(type) {
|
||||||
|
case digestReference:
|
||||||
|
if v2, ok := r2.(digestReference); ok {
|
||||||
|
return v1 == v2
|
||||||
|
}
|
||||||
|
case repository:
|
||||||
|
if v2, ok := r2.(repository); ok {
|
||||||
|
return v1 == v2
|
||||||
|
}
|
||||||
|
case taggedReference:
|
||||||
|
if v2, ok := r2.(taggedReference); ok {
|
||||||
|
return v1 == v2
|
||||||
|
}
|
||||||
|
case canonicalReference:
|
||||||
|
if v2, ok := r2.(canonicalReference); ok {
|
||||||
|
return v1 == v2
|
||||||
|
}
|
||||||
|
case reference:
|
||||||
|
if v2, ok := r2.(reference); ok {
|
||||||
|
return v1 == v2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseAnyReference(t *testing.T) {
|
||||||
|
tcases := []struct {
|
||||||
|
Reference string
|
||||||
|
Equivalent string
|
||||||
|
Expected Reference
|
||||||
|
Digests []digest.Digest
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Reference: "redis",
|
||||||
|
Equivalent: "docker.io/library/redis",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "redis:latest",
|
||||||
|
Equivalent: "docker.io/library/redis:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "docker.io/library/redis:latest",
|
||||||
|
Equivalent: "docker.io/library/redis:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "redis@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
Equivalent: "docker.io/library/redis@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "docker.io/library/redis@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
Equivalent: "docker.io/library/redis@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "dmcgowan/myapp",
|
||||||
|
Equivalent: "docker.io/dmcgowan/myapp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "dmcgowan/myapp:latest",
|
||||||
|
Equivalent: "docker.io/dmcgowan/myapp:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "docker.io/mcgowan/myapp:latest",
|
||||||
|
Equivalent: "docker.io/mcgowan/myapp:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "dmcgowan/myapp@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
Equivalent: "docker.io/dmcgowan/myapp@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "docker.io/dmcgowan/myapp@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
Equivalent: "docker.io/dmcgowan/myapp@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
Expected: digestReference("sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||||
|
Equivalent: "sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
Expected: digestReference("sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||||
|
Equivalent: "sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9",
|
||||||
|
Equivalent: "docker.io/library/dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9",
|
||||||
|
Expected: digestReference("sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||||
|
Equivalent: "sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
Digests: []digest.Digest{
|
||||||
|
digest.Digest("sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||||
|
digest.Digest("sha256:abcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9",
|
||||||
|
Equivalent: "docker.io/library/dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9",
|
||||||
|
Digests: []digest.Digest{
|
||||||
|
digest.Digest("sha256:abcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "dbcc1c",
|
||||||
|
Expected: digestReference("sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||||
|
Equivalent: "sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||||
|
Digests: []digest.Digest{
|
||||||
|
digest.Digest("sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||||
|
digest.Digest("sha256:abcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "dbcc1",
|
||||||
|
Equivalent: "docker.io/library/dbcc1",
|
||||||
|
Digests: []digest.Digest{
|
||||||
|
digest.Digest("sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||||
|
digest.Digest("sha256:abcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Reference: "dbcc1c",
|
||||||
|
Equivalent: "docker.io/library/dbcc1c",
|
||||||
|
Digests: []digest.Digest{
|
||||||
|
digest.Digest("sha256:abcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tcase := range tcases {
|
||||||
|
var ref Reference
|
||||||
|
var err error
|
||||||
|
if len(tcase.Digests) == 0 {
|
||||||
|
ref, err = ParseAnyReference(tcase.Reference)
|
||||||
|
} else {
|
||||||
|
ds := digestset.NewSet()
|
||||||
|
for _, dgst := range tcase.Digests {
|
||||||
|
if err := ds.Add(dgst); err != nil {
|
||||||
|
t.Fatalf("Error adding digest %s: %v", dgst.String(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ref, err = ParseAnyReferenceWithSet(tcase.Reference, ds)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error parsing reference %s: %v", tcase.Reference, err)
|
||||||
|
}
|
||||||
|
if ref.String() != tcase.Equivalent {
|
||||||
|
t.Fatalf("Unexpected string: %s, expected %s", ref.String(), tcase.Equivalent)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := tcase.Expected
|
||||||
|
if expected == nil {
|
||||||
|
expected, err = Parse(tcase.Equivalent)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error parsing reference %s: %v", tcase.Equivalent, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !equalReference(ref, expected) {
|
||||||
|
t.Errorf("Unexpected reference %#v, expected %#v", ref, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNormalizedSplitHostname(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
input string
|
||||||
|
domain string
|
||||||
|
name string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
input: "test.com/foo",
|
||||||
|
domain: "test.com",
|
||||||
|
name: "foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "test_com/foo",
|
||||||
|
domain: "docker.io",
|
||||||
|
name: "test_com/foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "docker/migrator",
|
||||||
|
domain: "docker.io",
|
||||||
|
name: "docker/migrator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "test.com:8080/foo",
|
||||||
|
domain: "test.com:8080",
|
||||||
|
name: "foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "test-com:8080/foo",
|
||||||
|
domain: "test-com:8080",
|
||||||
|
name: "foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "foo",
|
||||||
|
domain: "docker.io",
|
||||||
|
name: "library/foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "xn--n3h.com/foo",
|
||||||
|
domain: "xn--n3h.com",
|
||||||
|
name: "foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "xn--n3h.com:18080/foo",
|
||||||
|
domain: "xn--n3h.com:18080",
|
||||||
|
name: "foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "docker.io/foo",
|
||||||
|
domain: "docker.io",
|
||||||
|
name: "library/foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "docker.io/library/foo",
|
||||||
|
domain: "docker.io",
|
||||||
|
name: "library/foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "docker.io/library/foo/bar",
|
||||||
|
domain: "docker.io",
|
||||||
|
name: "library/foo/bar",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, testcase := range testcases {
|
||||||
|
failf := func(format string, v ...interface{}) {
|
||||||
|
t.Logf(strconv.Quote(testcase.input)+": "+format, v...)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
named, err := ParseNormalizedNamed(testcase.input)
|
||||||
|
if err != nil {
|
||||||
|
failf("error parsing name: %s", err)
|
||||||
|
}
|
||||||
|
domain, name := SplitHostname(named)
|
||||||
|
if domain != testcase.domain {
|
||||||
|
failf("unexpected domain: got %q, expected %q", domain, testcase.domain)
|
||||||
|
}
|
||||||
|
if name != testcase.name {
|
||||||
|
failf("unexpected name: got %q, expected %q", name, testcase.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMatchError(t *testing.T) {
|
||||||
|
named, err := ParseAnyReference("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = FamiliarMatch("[-x]", named)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected an error, got nothing")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMatch(t *testing.T) {
|
||||||
|
matchCases := []struct {
|
||||||
|
reference string
|
||||||
|
pattern string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
reference: "foo",
|
||||||
|
pattern: "foo/**/ba[rz]",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reference: "foo/any/bat",
|
||||||
|
pattern: "foo/**/ba[rz]",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reference: "foo/a/bar",
|
||||||
|
pattern: "foo/**/ba[rz]",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reference: "foo/b/baz",
|
||||||
|
pattern: "foo/**/ba[rz]",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reference: "foo/c/baz:tag",
|
||||||
|
pattern: "foo/**/ba[rz]",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reference: "foo/c/baz:tag",
|
||||||
|
pattern: "foo/*/baz:tag",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reference: "foo/c/baz:tag",
|
||||||
|
pattern: "foo/c/baz:tag",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reference: "example.com/foo/c/baz:tag",
|
||||||
|
pattern: "*/foo/c/baz",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reference: "example.com/foo/c/baz:tag",
|
||||||
|
pattern: "example.com/foo/c/baz",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, c := range matchCases {
|
||||||
|
named, err := ParseAnyReference(c.reference)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
actual, err := FamiliarMatch(c.pattern, named)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if actual != c.expected {
|
||||||
|
t.Fatalf("expected %s match %s to be %v, was %v", c.reference, c.pattern, c.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
191
vendor/github.com/docker/distribution/reference/reference.go
generated
vendored
191
vendor/github.com/docker/distribution/reference/reference.go
generated
vendored
@@ -4,30 +4,32 @@
|
|||||||
// Grammar
|
// Grammar
|
||||||
//
|
//
|
||||||
// reference := name [ ":" tag ] [ "@" digest ]
|
// reference := name [ ":" tag ] [ "@" digest ]
|
||||||
// name := [hostname '/'] component ['/' component]*
|
// name := [domain '/'] path-component ['/' path-component]*
|
||||||
// hostname := hostcomponent ['.' hostcomponent]* [':' port-number]
|
// domain := domain-component ['.' domain-component]* [':' port-number]
|
||||||
// hostcomponent := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
|
// domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
|
||||||
// port-number := /[0-9]+/
|
// port-number := /[0-9]+/
|
||||||
// component := alpha-numeric [separator alpha-numeric]*
|
// path-component := alpha-numeric [separator alpha-numeric]*
|
||||||
// alpha-numeric := /[a-z0-9]+/
|
// alpha-numeric := /[a-z0-9]+/
|
||||||
// separator := /[_.]|__|[-]*/
|
// separator := /[_.]|__|[-]*/
|
||||||
//
|
//
|
||||||
// tag := /[\w][\w.-]{0,127}/
|
// tag := /[\w][\w.-]{0,127}/
|
||||||
//
|
//
|
||||||
// digest := digest-algorithm ":" digest-hex
|
// digest := digest-algorithm ":" digest-hex
|
||||||
// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]
|
// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]*
|
||||||
// digest-algorithm-separator := /[+.-_]/
|
// digest-algorithm-separator := /[+.-_]/
|
||||||
// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/
|
// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/
|
||||||
// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
|
// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
|
||||||
|
//
|
||||||
|
// identifier := /[a-f0-9]{64}/
|
||||||
|
// short-identifier := /[a-f0-9]{6,64}/
|
||||||
package reference
|
package reference
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -53,6 +55,9 @@ var (
|
|||||||
|
|
||||||
// ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax.
|
// ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax.
|
||||||
ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax)
|
ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax)
|
||||||
|
|
||||||
|
// ErrNameNotCanonical is returned when a name is not canonical.
|
||||||
|
ErrNameNotCanonical = errors.New("repository name must be canonical")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reference is an opaque object reference identifier that may include
|
// Reference is an opaque object reference identifier that may include
|
||||||
@@ -126,23 +131,56 @@ type Digested interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Canonical reference is an object with a fully unique
|
// Canonical reference is an object with a fully unique
|
||||||
// name including a name with hostname and digest
|
// name including a name with domain and digest
|
||||||
type Canonical interface {
|
type Canonical interface {
|
||||||
Named
|
Named
|
||||||
Digest() digest.Digest
|
Digest() digest.Digest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// namedRepository is a reference to a repository with a name.
|
||||||
|
// A namedRepository has both domain and path components.
|
||||||
|
type namedRepository interface {
|
||||||
|
Named
|
||||||
|
Domain() string
|
||||||
|
Path() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Domain returns the domain part of the Named reference
|
||||||
|
func Domain(named Named) string {
|
||||||
|
if r, ok := named.(namedRepository); ok {
|
||||||
|
return r.Domain()
|
||||||
|
}
|
||||||
|
domain, _ := splitDomain(named.Name())
|
||||||
|
return domain
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path returns the name without the domain part of the Named reference
|
||||||
|
func Path(named Named) (name string) {
|
||||||
|
if r, ok := named.(namedRepository); ok {
|
||||||
|
return r.Path()
|
||||||
|
}
|
||||||
|
_, path := splitDomain(named.Name())
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitDomain(name string) (string, string) {
|
||||||
|
match := anchoredNameRegexp.FindStringSubmatch(name)
|
||||||
|
if len(match) != 3 {
|
||||||
|
return "", name
|
||||||
|
}
|
||||||
|
return match[1], match[2]
|
||||||
|
}
|
||||||
|
|
||||||
// SplitHostname splits a named reference into a
|
// SplitHostname splits a named reference into a
|
||||||
// hostname and name string. If no valid hostname is
|
// hostname and name string. If no valid hostname is
|
||||||
// found, the hostname is empty and the full value
|
// found, the hostname is empty and the full value
|
||||||
// is returned as name
|
// is returned as name
|
||||||
|
// DEPRECATED: Use Domain or Path
|
||||||
func SplitHostname(named Named) (string, string) {
|
func SplitHostname(named Named) (string, string) {
|
||||||
name := named.Name()
|
if r, ok := named.(namedRepository); ok {
|
||||||
match := anchoredNameRegexp.FindStringSubmatch(name)
|
return r.Domain(), r.Path()
|
||||||
if len(match) != 3 {
|
|
||||||
return "", name
|
|
||||||
}
|
}
|
||||||
return match[1], match[2]
|
return splitDomain(named.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses s and returns a syntactically valid Reference.
|
// Parse parses s and returns a syntactically valid Reference.
|
||||||
@@ -164,13 +202,24 @@ func Parse(s string) (Reference, error) {
|
|||||||
return nil, ErrNameTooLong
|
return nil, ErrNameTooLong
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var repo repository
|
||||||
|
|
||||||
|
nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1])
|
||||||
|
if nameMatch != nil && len(nameMatch) == 3 {
|
||||||
|
repo.domain = nameMatch[1]
|
||||||
|
repo.path = nameMatch[2]
|
||||||
|
} else {
|
||||||
|
repo.domain = ""
|
||||||
|
repo.path = matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
ref := reference{
|
ref := reference{
|
||||||
name: matches[1],
|
namedRepository: repo,
|
||||||
tag: matches[2],
|
tag: matches[2],
|
||||||
}
|
}
|
||||||
if matches[3] != "" {
|
if matches[3] != "" {
|
||||||
var err error
|
var err error
|
||||||
ref.digest, err = digest.ParseDigest(matches[3])
|
ref.digest, err = digest.Parse(matches[3])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -185,18 +234,17 @@ func Parse(s string) (Reference, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParseNamed parses s and returns a syntactically valid reference implementing
|
// ParseNamed parses s and returns a syntactically valid reference implementing
|
||||||
// the Named interface. The reference must have a name, otherwise an error is
|
// the Named interface. The reference must have a name and be in the canonical
|
||||||
// returned.
|
// form, otherwise an error is returned.
|
||||||
// If an error was encountered it is returned, along with a nil Reference.
|
// If an error was encountered it is returned, along with a nil Reference.
|
||||||
// NOTE: ParseNamed will not handle short digests.
|
// NOTE: ParseNamed will not handle short digests.
|
||||||
func ParseNamed(s string) (Named, error) {
|
func ParseNamed(s string) (Named, error) {
|
||||||
ref, err := Parse(s)
|
named, err := ParseNormalizedNamed(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
named, isNamed := ref.(Named)
|
if named.String() != s {
|
||||||
if !isNamed {
|
return nil, ErrNameNotCanonical
|
||||||
return nil, fmt.Errorf("reference %s has no name", ref.String())
|
|
||||||
}
|
}
|
||||||
return named, nil
|
return named, nil
|
||||||
}
|
}
|
||||||
@@ -207,10 +255,15 @@ func WithName(name string) (Named, error) {
|
|||||||
if len(name) > NameTotalLengthMax {
|
if len(name) > NameTotalLengthMax {
|
||||||
return nil, ErrNameTooLong
|
return nil, ErrNameTooLong
|
||||||
}
|
}
|
||||||
if !anchoredNameRegexp.MatchString(name) {
|
|
||||||
|
match := anchoredNameRegexp.FindStringSubmatch(name)
|
||||||
|
if match == nil || len(match) != 3 {
|
||||||
return nil, ErrReferenceInvalidFormat
|
return nil, ErrReferenceInvalidFormat
|
||||||
}
|
}
|
||||||
return repository(name), nil
|
return repository{
|
||||||
|
domain: match[1],
|
||||||
|
path: match[2],
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithTag combines the name from "name" and the tag from "tag" to form a
|
// WithTag combines the name from "name" and the tag from "tag" to form a
|
||||||
@@ -219,15 +272,22 @@ func WithTag(name Named, tag string) (NamedTagged, error) {
|
|||||||
if !anchoredTagRegexp.MatchString(tag) {
|
if !anchoredTagRegexp.MatchString(tag) {
|
||||||
return nil, ErrTagInvalidFormat
|
return nil, ErrTagInvalidFormat
|
||||||
}
|
}
|
||||||
|
var repo repository
|
||||||
|
if r, ok := name.(namedRepository); ok {
|
||||||
|
repo.domain = r.Domain()
|
||||||
|
repo.path = r.Path()
|
||||||
|
} else {
|
||||||
|
repo.path = name.Name()
|
||||||
|
}
|
||||||
if canonical, ok := name.(Canonical); ok {
|
if canonical, ok := name.(Canonical); ok {
|
||||||
return reference{
|
return reference{
|
||||||
name: name.Name(),
|
namedRepository: repo,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
digest: canonical.Digest(),
|
digest: canonical.Digest(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
return taggedReference{
|
return taggedReference{
|
||||||
name: name.Name(),
|
namedRepository: repo,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -238,36 +298,37 @@ func WithDigest(name Named, digest digest.Digest) (Canonical, error) {
|
|||||||
if !anchoredDigestRegexp.MatchString(digest.String()) {
|
if !anchoredDigestRegexp.MatchString(digest.String()) {
|
||||||
return nil, ErrDigestInvalidFormat
|
return nil, ErrDigestInvalidFormat
|
||||||
}
|
}
|
||||||
|
var repo repository
|
||||||
|
if r, ok := name.(namedRepository); ok {
|
||||||
|
repo.domain = r.Domain()
|
||||||
|
repo.path = r.Path()
|
||||||
|
} else {
|
||||||
|
repo.path = name.Name()
|
||||||
|
}
|
||||||
if tagged, ok := name.(Tagged); ok {
|
if tagged, ok := name.(Tagged); ok {
|
||||||
return reference{
|
return reference{
|
||||||
name: name.Name(),
|
namedRepository: repo,
|
||||||
tag: tagged.Tag(),
|
tag: tagged.Tag(),
|
||||||
digest: digest,
|
digest: digest,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
return canonicalReference{
|
return canonicalReference{
|
||||||
name: name.Name(),
|
namedRepository: repo,
|
||||||
digest: digest,
|
digest: digest,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match reports whether ref matches the specified pattern.
|
|
||||||
// See https://godoc.org/path#Match for supported patterns.
|
|
||||||
func Match(pattern string, ref Reference) (bool, error) {
|
|
||||||
matched, err := path.Match(pattern, ref.String())
|
|
||||||
if namedRef, isNamed := ref.(Named); isNamed && !matched {
|
|
||||||
matched, _ = path.Match(pattern, namedRef.Name())
|
|
||||||
}
|
|
||||||
return matched, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TrimNamed removes any tag or digest from the named reference.
|
// TrimNamed removes any tag or digest from the named reference.
|
||||||
func TrimNamed(ref Named) Named {
|
func TrimNamed(ref Named) Named {
|
||||||
return repository(ref.Name())
|
domain, path := SplitHostname(ref)
|
||||||
|
return repository{
|
||||||
|
domain: domain,
|
||||||
|
path: path,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBestReferenceType(ref reference) Reference {
|
func getBestReferenceType(ref reference) Reference {
|
||||||
if ref.name == "" {
|
if ref.Name() == "" {
|
||||||
// Allow digest only references
|
// Allow digest only references
|
||||||
if ref.digest != "" {
|
if ref.digest != "" {
|
||||||
return digestReference(ref.digest)
|
return digestReference(ref.digest)
|
||||||
@@ -277,15 +338,15 @@ func getBestReferenceType(ref reference) Reference {
|
|||||||
if ref.tag == "" {
|
if ref.tag == "" {
|
||||||
if ref.digest != "" {
|
if ref.digest != "" {
|
||||||
return canonicalReference{
|
return canonicalReference{
|
||||||
name: ref.name,
|
namedRepository: ref.namedRepository,
|
||||||
digest: ref.digest,
|
digest: ref.digest,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return repository(ref.name)
|
return ref.namedRepository
|
||||||
}
|
}
|
||||||
if ref.digest == "" {
|
if ref.digest == "" {
|
||||||
return taggedReference{
|
return taggedReference{
|
||||||
name: ref.name,
|
namedRepository: ref.namedRepository,
|
||||||
tag: ref.tag,
|
tag: ref.tag,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,17 +355,13 @@ func getBestReferenceType(ref reference) Reference {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type reference struct {
|
type reference struct {
|
||||||
name string
|
namedRepository
|
||||||
tag string
|
tag string
|
||||||
digest digest.Digest
|
digest digest.Digest
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r reference) String() string {
|
func (r reference) String() string {
|
||||||
return r.name + ":" + r.tag + "@" + r.digest.String()
|
return r.Name() + ":" + r.tag + "@" + r.digest.String()
|
||||||
}
|
|
||||||
|
|
||||||
func (r reference) Name() string {
|
|
||||||
return r.name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r reference) Tag() string {
|
func (r reference) Tag() string {
|
||||||
@@ -315,20 +372,34 @@ func (r reference) Digest() digest.Digest {
|
|||||||
return r.digest
|
return r.digest
|
||||||
}
|
}
|
||||||
|
|
||||||
type repository string
|
type repository struct {
|
||||||
|
domain string
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
func (r repository) String() string {
|
func (r repository) String() string {
|
||||||
return string(r)
|
return r.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r repository) Name() string {
|
func (r repository) Name() string {
|
||||||
return string(r)
|
if r.domain == "" {
|
||||||
|
return r.path
|
||||||
|
}
|
||||||
|
return r.domain + "/" + r.path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r repository) Domain() string {
|
||||||
|
return r.domain
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r repository) Path() string {
|
||||||
|
return r.path
|
||||||
}
|
}
|
||||||
|
|
||||||
type digestReference digest.Digest
|
type digestReference digest.Digest
|
||||||
|
|
||||||
func (d digestReference) String() string {
|
func (d digestReference) String() string {
|
||||||
return d.String()
|
return digest.Digest(d).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d digestReference) Digest() digest.Digest {
|
func (d digestReference) Digest() digest.Digest {
|
||||||
@@ -336,16 +407,12 @@ func (d digestReference) Digest() digest.Digest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type taggedReference struct {
|
type taggedReference struct {
|
||||||
name string
|
namedRepository
|
||||||
tag string
|
tag string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t taggedReference) String() string {
|
func (t taggedReference) String() string {
|
||||||
return t.name + ":" + t.tag
|
return t.Name() + ":" + t.tag
|
||||||
}
|
|
||||||
|
|
||||||
func (t taggedReference) Name() string {
|
|
||||||
return t.name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t taggedReference) Tag() string {
|
func (t taggedReference) Tag() string {
|
||||||
@@ -353,16 +420,12 @@ func (t taggedReference) Tag() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type canonicalReference struct {
|
type canonicalReference struct {
|
||||||
name string
|
namedRepository
|
||||||
digest digest.Digest
|
digest digest.Digest
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c canonicalReference) String() string {
|
func (c canonicalReference) String() string {
|
||||||
return c.name + "@" + c.digest.String()
|
return c.Name() + "@" + c.digest.String()
|
||||||
}
|
|
||||||
|
|
||||||
func (c canonicalReference) Name() string {
|
|
||||||
return c.name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c canonicalReference) Digest() digest.Digest {
|
func (c canonicalReference) Digest() digest.Digest {
|
||||||
|
|||||||
166
vendor/github.com/docker/distribution/reference/reference_test.go
generated
vendored
166
vendor/github.com/docker/distribution/reference/reference_test.go
generated
vendored
@@ -1,12 +1,14 @@
|
|||||||
package reference
|
package reference
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
_ "crypto/sha256"
|
||||||
|
_ "crypto/sha512"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestReferenceParse(t *testing.T) {
|
func TestReferenceParse(t *testing.T) {
|
||||||
@@ -19,8 +21,8 @@ func TestReferenceParse(t *testing.T) {
|
|||||||
err error
|
err error
|
||||||
// repository is the string representation for the reference
|
// repository is the string representation for the reference
|
||||||
repository string
|
repository string
|
||||||
// hostname is the hostname expected in the reference
|
// domain is the domain expected in the reference
|
||||||
hostname string
|
domain string
|
||||||
// tag is the tag for the reference
|
// tag is the tag for the reference
|
||||||
tag string
|
tag string
|
||||||
// digest is the digest for the reference (enforces digest reference)
|
// digest is the digest for the reference (enforces digest reference)
|
||||||
@@ -42,37 +44,37 @@ func TestReferenceParse(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "test.com/repo:tag",
|
input: "test.com/repo:tag",
|
||||||
hostname: "test.com",
|
domain: "test.com",
|
||||||
repository: "test.com/repo",
|
repository: "test.com/repo",
|
||||||
tag: "tag",
|
tag: "tag",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "test:5000/repo",
|
input: "test:5000/repo",
|
||||||
hostname: "test:5000",
|
domain: "test:5000",
|
||||||
repository: "test:5000/repo",
|
repository: "test:5000/repo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "test:5000/repo:tag",
|
input: "test:5000/repo:tag",
|
||||||
hostname: "test:5000",
|
domain: "test:5000",
|
||||||
repository: "test:5000/repo",
|
repository: "test:5000/repo",
|
||||||
tag: "tag",
|
tag: "tag",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "test:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
input: "test:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
hostname: "test:5000",
|
domain: "test:5000",
|
||||||
repository: "test:5000/repo",
|
repository: "test:5000/repo",
|
||||||
digest: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
digest: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "test:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
input: "test:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
hostname: "test:5000",
|
domain: "test:5000",
|
||||||
repository: "test:5000/repo",
|
repository: "test:5000/repo",
|
||||||
tag: "tag",
|
tag: "tag",
|
||||||
digest: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
digest: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "test:5000/repo",
|
input: "test:5000/repo",
|
||||||
hostname: "test:5000",
|
domain: "test:5000",
|
||||||
repository: "test:5000/repo",
|
repository: "test:5000/repo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -120,7 +122,7 @@ func TestReferenceParse(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: strings.Repeat("a/", 127) + "a:tag-puts-this-over-max",
|
input: strings.Repeat("a/", 127) + "a:tag-puts-this-over-max",
|
||||||
hostname: "a",
|
domain: "a",
|
||||||
repository: strings.Repeat("a/", 127) + "a",
|
repository: strings.Repeat("a/", 127) + "a",
|
||||||
tag: "tag-puts-this-over-max",
|
tag: "tag-puts-this-over-max",
|
||||||
},
|
},
|
||||||
@@ -130,30 +132,30 @@ func TestReferenceParse(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "sub-dom1.foo.com/bar/baz/quux",
|
input: "sub-dom1.foo.com/bar/baz/quux",
|
||||||
hostname: "sub-dom1.foo.com",
|
domain: "sub-dom1.foo.com",
|
||||||
repository: "sub-dom1.foo.com/bar/baz/quux",
|
repository: "sub-dom1.foo.com/bar/baz/quux",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "sub-dom1.foo.com/bar/baz/quux:some-long-tag",
|
input: "sub-dom1.foo.com/bar/baz/quux:some-long-tag",
|
||||||
hostname: "sub-dom1.foo.com",
|
domain: "sub-dom1.foo.com",
|
||||||
repository: "sub-dom1.foo.com/bar/baz/quux",
|
repository: "sub-dom1.foo.com/bar/baz/quux",
|
||||||
tag: "some-long-tag",
|
tag: "some-long-tag",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "b.gcr.io/test.example.com/my-app:test.example.com",
|
input: "b.gcr.io/test.example.com/my-app:test.example.com",
|
||||||
hostname: "b.gcr.io",
|
domain: "b.gcr.io",
|
||||||
repository: "b.gcr.io/test.example.com/my-app",
|
repository: "b.gcr.io/test.example.com/my-app",
|
||||||
tag: "test.example.com",
|
tag: "test.example.com",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "xn--n3h.com/myimage:xn--n3h.com", // ☃.com in punycode
|
input: "xn--n3h.com/myimage:xn--n3h.com", // ☃.com in punycode
|
||||||
hostname: "xn--n3h.com",
|
domain: "xn--n3h.com",
|
||||||
repository: "xn--n3h.com/myimage",
|
repository: "xn--n3h.com/myimage",
|
||||||
tag: "xn--n3h.com",
|
tag: "xn--n3h.com",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "xn--7o8h.com/myimage:xn--7o8h.com@sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // 🐳.com in punycode
|
input: "xn--7o8h.com/myimage:xn--7o8h.com@sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // 🐳.com in punycode
|
||||||
hostname: "xn--7o8h.com",
|
domain: "xn--7o8h.com",
|
||||||
repository: "xn--7o8h.com/myimage",
|
repository: "xn--7o8h.com/myimage",
|
||||||
tag: "xn--7o8h.com",
|
tag: "xn--7o8h.com",
|
||||||
digest: "sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
digest: "sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
@@ -165,7 +167,7 @@ func TestReferenceParse(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "foo/foo_bar.com:8080",
|
input: "foo/foo_bar.com:8080",
|
||||||
hostname: "foo",
|
domain: "foo",
|
||||||
repository: "foo/foo_bar.com",
|
repository: "foo/foo_bar.com",
|
||||||
tag: "8080",
|
tag: "8080",
|
||||||
},
|
},
|
||||||
@@ -196,11 +198,11 @@ func TestReferenceParse(t *testing.T) {
|
|||||||
if named.Name() != testcase.repository {
|
if named.Name() != testcase.repository {
|
||||||
failf("unexpected repository: got %q, expected %q", named.Name(), testcase.repository)
|
failf("unexpected repository: got %q, expected %q", named.Name(), testcase.repository)
|
||||||
}
|
}
|
||||||
hostname, _ := SplitHostname(named)
|
domain, _ := SplitHostname(named)
|
||||||
if hostname != testcase.hostname {
|
if domain != testcase.domain {
|
||||||
failf("unexpected hostname: got %q, expected %q", hostname, testcase.hostname)
|
failf("unexpected domain: got %q, expected %q", domain, testcase.domain)
|
||||||
}
|
}
|
||||||
} else if testcase.repository != "" || testcase.hostname != "" {
|
} else if testcase.repository != "" || testcase.domain != "" {
|
||||||
failf("expected named type, got %T", repo)
|
failf("expected named type, got %T", repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,37 +283,37 @@ func TestWithNameFailure(t *testing.T) {
|
|||||||
func TestSplitHostname(t *testing.T) {
|
func TestSplitHostname(t *testing.T) {
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
input string
|
input string
|
||||||
hostname string
|
domain string
|
||||||
name string
|
name string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
input: "test.com/foo",
|
input: "test.com/foo",
|
||||||
hostname: "test.com",
|
domain: "test.com",
|
||||||
name: "foo",
|
name: "foo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "test_com/foo",
|
input: "test_com/foo",
|
||||||
hostname: "",
|
domain: "",
|
||||||
name: "test_com/foo",
|
name: "test_com/foo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "test:8080/foo",
|
input: "test:8080/foo",
|
||||||
hostname: "test:8080",
|
domain: "test:8080",
|
||||||
name: "foo",
|
name: "foo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "test.com:8080/foo",
|
input: "test.com:8080/foo",
|
||||||
hostname: "test.com:8080",
|
domain: "test.com:8080",
|
||||||
name: "foo",
|
name: "foo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "test-com:8080/foo",
|
input: "test-com:8080/foo",
|
||||||
hostname: "test-com:8080",
|
domain: "test-com:8080",
|
||||||
name: "foo",
|
name: "foo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "xn--n3h.com:18080/foo",
|
input: "xn--n3h.com:18080/foo",
|
||||||
hostname: "xn--n3h.com:18080",
|
domain: "xn--n3h.com:18080",
|
||||||
name: "foo",
|
name: "foo",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -325,9 +327,9 @@ func TestSplitHostname(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
failf("error parsing name: %s", err)
|
failf("error parsing name: %s", err)
|
||||||
}
|
}
|
||||||
hostname, name := SplitHostname(named)
|
domain, name := SplitHostname(named)
|
||||||
if hostname != testcase.hostname {
|
if domain != testcase.domain {
|
||||||
failf("unexpected hostname: got %q, expected %q", hostname, testcase.hostname)
|
failf("unexpected domain: got %q, expected %q", domain, testcase.domain)
|
||||||
}
|
}
|
||||||
if name != testcase.name {
|
if name != testcase.name {
|
||||||
failf("unexpected name: got %q, expected %q", name, testcase.name)
|
failf("unexpected name: got %q, expected %q", name, testcase.name)
|
||||||
@@ -582,80 +584,76 @@ func TestWithDigest(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMatchError(t *testing.T) {
|
func TestParseNamed(t *testing.T) {
|
||||||
named, err := Parse("foo")
|
testcases := []struct {
|
||||||
if err != nil {
|
input string
|
||||||
t.Fatal(err)
|
domain string
|
||||||
}
|
name string
|
||||||
_, err = Match("[-x]", named)
|
err error
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("expected an error, got nothing")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMatch(t *testing.T) {
|
|
||||||
matchCases := []struct {
|
|
||||||
reference string
|
|
||||||
pattern string
|
|
||||||
expected bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
reference: "foo",
|
input: "test.com/foo",
|
||||||
pattern: "foo/**/ba[rz]",
|
domain: "test.com",
|
||||||
expected: false,
|
name: "foo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
reference: "foo/any/bat",
|
input: "test:8080/foo",
|
||||||
pattern: "foo/**/ba[rz]",
|
domain: "test:8080",
|
||||||
expected: false,
|
name: "foo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
reference: "foo/a/bar",
|
input: "test_com/foo",
|
||||||
pattern: "foo/**/ba[rz]",
|
err: ErrNameNotCanonical,
|
||||||
expected: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
reference: "foo/b/baz",
|
input: "test.com",
|
||||||
pattern: "foo/**/ba[rz]",
|
err: ErrNameNotCanonical,
|
||||||
expected: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
reference: "foo/c/baz:tag",
|
input: "foo",
|
||||||
pattern: "foo/**/ba[rz]",
|
err: ErrNameNotCanonical,
|
||||||
expected: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
reference: "foo/c/baz:tag",
|
input: "library/foo",
|
||||||
pattern: "foo/*/baz:tag",
|
err: ErrNameNotCanonical,
|
||||||
expected: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
reference: "foo/c/baz:tag",
|
input: "docker.io/library/foo",
|
||||||
pattern: "foo/c/baz:tag",
|
domain: "docker.io",
|
||||||
expected: true,
|
name: "library/foo",
|
||||||
},
|
},
|
||||||
|
// Ambiguous case, parser will add "library/" to foo
|
||||||
{
|
{
|
||||||
reference: "example.com/foo/c/baz:tag",
|
input: "docker.io/foo",
|
||||||
pattern: "*/foo/c/baz",
|
err: ErrNameNotCanonical,
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
reference: "example.com/foo/c/baz:tag",
|
|
||||||
pattern: "example.com/foo/c/baz",
|
|
||||||
expected: true,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, c := range matchCases {
|
for _, testcase := range testcases {
|
||||||
named, err := Parse(c.reference)
|
failf := func(format string, v ...interface{}) {
|
||||||
if err != nil {
|
t.Logf(strconv.Quote(testcase.input)+": "+format, v...)
|
||||||
t.Fatal(err)
|
t.Fail()
|
||||||
}
|
}
|
||||||
actual, err := Match(c.pattern, named)
|
|
||||||
if err != nil {
|
named, err := ParseNamed(testcase.input)
|
||||||
t.Fatal(err)
|
if err != nil && testcase.err == nil {
|
||||||
|
failf("error parsing name: %s", err)
|
||||||
|
continue
|
||||||
|
} else if err == nil && testcase.err != nil {
|
||||||
|
failf("parsing succeded: expected error %v", testcase.err)
|
||||||
|
continue
|
||||||
|
} else if err != testcase.err {
|
||||||
|
failf("unexpected error %v, expected %v", err, testcase.err)
|
||||||
|
continue
|
||||||
|
} else if err != nil {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
if actual != c.expected {
|
|
||||||
t.Fatalf("expected %s match %s to be %v, was %v", c.reference, c.pattern, c.expected, actual)
|
domain, name := SplitHostname(named)
|
||||||
|
if domain != testcase.domain {
|
||||||
|
failf("unexpected domain: got %q, expected %q", domain, testcase.domain)
|
||||||
|
}
|
||||||
|
if name != testcase.name {
|
||||||
|
failf("unexpected name: got %q, expected %q", name, testcase.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
41
vendor/github.com/docker/distribution/reference/regexp.go
generated
vendored
41
vendor/github.com/docker/distribution/reference/regexp.go
generated
vendored
@@ -19,18 +19,18 @@ var (
|
|||||||
alphaNumericRegexp,
|
alphaNumericRegexp,
|
||||||
optional(repeated(separatorRegexp, alphaNumericRegexp)))
|
optional(repeated(separatorRegexp, alphaNumericRegexp)))
|
||||||
|
|
||||||
// hostnameComponentRegexp restricts the registry hostname component of a
|
// domainComponentRegexp restricts the registry domain component of a
|
||||||
// repository name to start with a component as defined by hostnameRegexp
|
// repository name to start with a component as defined by DomainRegexp
|
||||||
// and followed by an optional port.
|
// and followed by an optional port.
|
||||||
hostnameComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`)
|
domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`)
|
||||||
|
|
||||||
// hostnameRegexp defines the structure of potential hostname components
|
// DomainRegexp defines the structure of potential domain components
|
||||||
// that may be part of image names. This is purposely a subset of what is
|
// that may be part of image names. This is purposely a subset of what is
|
||||||
// allowed by DNS to ensure backwards compatibility with Docker image
|
// allowed by DNS to ensure backwards compatibility with Docker image
|
||||||
// names.
|
// names.
|
||||||
hostnameRegexp = expression(
|
DomainRegexp = expression(
|
||||||
hostnameComponentRegexp,
|
domainComponentRegexp,
|
||||||
optional(repeated(literal(`.`), hostnameComponentRegexp)),
|
optional(repeated(literal(`.`), domainComponentRegexp)),
|
||||||
optional(literal(`:`), match(`[0-9]+`)))
|
optional(literal(`:`), match(`[0-9]+`)))
|
||||||
|
|
||||||
// TagRegexp matches valid tag names. From docker/docker:graph/tags.go.
|
// TagRegexp matches valid tag names. From docker/docker:graph/tags.go.
|
||||||
@@ -48,17 +48,17 @@ var (
|
|||||||
anchoredDigestRegexp = anchored(DigestRegexp)
|
anchoredDigestRegexp = anchored(DigestRegexp)
|
||||||
|
|
||||||
// NameRegexp is the format for the name component of references. The
|
// NameRegexp is the format for the name component of references. The
|
||||||
// regexp has capturing groups for the hostname and name part omitting
|
// regexp has capturing groups for the domain and name part omitting
|
||||||
// the separating forward slash from either.
|
// the separating forward slash from either.
|
||||||
NameRegexp = expression(
|
NameRegexp = expression(
|
||||||
optional(hostnameRegexp, literal(`/`)),
|
optional(DomainRegexp, literal(`/`)),
|
||||||
nameComponentRegexp,
|
nameComponentRegexp,
|
||||||
optional(repeated(literal(`/`), nameComponentRegexp)))
|
optional(repeated(literal(`/`), nameComponentRegexp)))
|
||||||
|
|
||||||
// anchoredNameRegexp is used to parse a name value, capturing the
|
// anchoredNameRegexp is used to parse a name value, capturing the
|
||||||
// hostname and trailing components.
|
// domain and trailing components.
|
||||||
anchoredNameRegexp = anchored(
|
anchoredNameRegexp = anchored(
|
||||||
optional(capture(hostnameRegexp), literal(`/`)),
|
optional(capture(DomainRegexp), literal(`/`)),
|
||||||
capture(nameComponentRegexp,
|
capture(nameComponentRegexp,
|
||||||
optional(repeated(literal(`/`), nameComponentRegexp))))
|
optional(repeated(literal(`/`), nameComponentRegexp))))
|
||||||
|
|
||||||
@@ -68,6 +68,25 @@ var (
|
|||||||
ReferenceRegexp = anchored(capture(NameRegexp),
|
ReferenceRegexp = anchored(capture(NameRegexp),
|
||||||
optional(literal(":"), capture(TagRegexp)),
|
optional(literal(":"), capture(TagRegexp)),
|
||||||
optional(literal("@"), capture(DigestRegexp)))
|
optional(literal("@"), capture(DigestRegexp)))
|
||||||
|
|
||||||
|
// IdentifierRegexp is the format for string identifier used as a
|
||||||
|
// content addressable identifier using sha256. These identifiers
|
||||||
|
// are like digests without the algorithm, since sha256 is used.
|
||||||
|
IdentifierRegexp = match(`([a-f0-9]{64})`)
|
||||||
|
|
||||||
|
// ShortIdentifierRegexp is the format used to represent a prefix
|
||||||
|
// of an identifier. A prefix may be used to match a sha256 identifier
|
||||||
|
// within a list of trusted identifiers.
|
||||||
|
ShortIdentifierRegexp = match(`([a-f0-9]{6,64})`)
|
||||||
|
|
||||||
|
// anchoredIdentifierRegexp is used to check or match an
|
||||||
|
// identifier value, anchored at start and end of string.
|
||||||
|
anchoredIdentifierRegexp = anchored(IdentifierRegexp)
|
||||||
|
|
||||||
|
// anchoredShortIdentifierRegexp is used to check if a value
|
||||||
|
// is a possible identifier prefix, anchored at start and end
|
||||||
|
// of string.
|
||||||
|
anchoredShortIdentifierRegexp = anchored(ShortIdentifierRegexp)
|
||||||
)
|
)
|
||||||
|
|
||||||
// match compiles the string to a regular expression.
|
// match compiles the string to a regular expression.
|
||||||
|
|||||||
68
vendor/github.com/docker/distribution/reference/regexp_test.go
generated
vendored
68
vendor/github.com/docker/distribution/reference/regexp_test.go
generated
vendored
@@ -33,7 +33,7 @@ func checkRegexp(t *testing.T, r *regexp.Regexp, m regexpMatch) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHostRegexp(t *testing.T) {
|
func TestDomainRegexp(t *testing.T) {
|
||||||
hostcases := []regexpMatch{
|
hostcases := []regexpMatch{
|
||||||
{
|
{
|
||||||
input: "test.com",
|
input: "test.com",
|
||||||
@@ -116,7 +116,7 @@ func TestHostRegexp(t *testing.T) {
|
|||||||
match: true,
|
match: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
r := regexp.MustCompile(`^` + hostnameRegexp.String() + `$`)
|
r := regexp.MustCompile(`^` + DomainRegexp.String() + `$`)
|
||||||
for i := range hostcases {
|
for i := range hostcases {
|
||||||
checkRegexp(t, r, hostcases[i])
|
checkRegexp(t, r, hostcases[i])
|
||||||
}
|
}
|
||||||
@@ -487,3 +487,67 @@ func TestReferenceRegexp(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIdentifierRegexp(t *testing.T) {
|
||||||
|
fullCases := []regexpMatch{
|
||||||
|
{
|
||||||
|
input: "da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf9821",
|
||||||
|
match: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "7EC43B381E5AEFE6E04EFB0B3F0693FF2A4A50652D64AEC573905F2DB5889A1C",
|
||||||
|
match: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf",
|
||||||
|
match: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "sha256:da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf9821",
|
||||||
|
match: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf98218482",
|
||||||
|
match: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
shortCases := []regexpMatch{
|
||||||
|
{
|
||||||
|
input: "da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf9821",
|
||||||
|
match: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "7EC43B381E5AEFE6E04EFB0B3F0693FF2A4A50652D64AEC573905F2DB5889A1C",
|
||||||
|
match: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf",
|
||||||
|
match: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "sha256:da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf9821",
|
||||||
|
match: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf98218482",
|
||||||
|
match: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "da304",
|
||||||
|
match: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "da304e",
|
||||||
|
match: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range fullCases {
|
||||||
|
checkRegexp(t, anchoredIdentifierRegexp, fullCases[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range shortCases {
|
||||||
|
checkRegexp(t, anchoredShortIdentifierRegexp, shortCases[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/registry.go
generated
vendored
2
vendor/github.com/docker/distribution/registry.go
generated
vendored
@@ -35,7 +35,7 @@ type Namespace interface {
|
|||||||
// reference.
|
// reference.
|
||||||
Repository(ctx context.Context, name reference.Named) (Repository, error)
|
Repository(ctx context.Context, name reference.Named) (Repository, error)
|
||||||
|
|
||||||
// Repositories fills 'repos' with a lexigraphically sorted catalog of repositories
|
// Repositories fills 'repos' with a lexicographically sorted catalog of repositories
|
||||||
// up to the size of 'repos' and returns the value 'n' for the number of entries
|
// up to the size of 'repos' and returns the value 'n' for the number of entries
|
||||||
// which were filled. 'last' contains an offset in the catalog, and 'err' will be
|
// which were filled. 'last' contains an offset in the catalog, and 'err' will be
|
||||||
// set to io.EOF if there are no more entries to obtain.
|
// set to io.EOF if there are no more entries to obtain.
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/registry/api/v2/descriptors.go
generated
vendored
2
vendor/github.com/docker/distribution/registry/api/v2/descriptors.go
generated
vendored
@@ -4,9 +4,9 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/api/errcode"
|
"github.com/docker/distribution/registry/api/errcode"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
3
vendor/github.com/docker/distribution/registry/api/v2/urls.go
generated
vendored
3
vendor/github.com/docker/distribution/registry/api/v2/urls.go
generated
vendored
@@ -1,6 +1,7 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -149,6 +150,8 @@ func (ub *URLBuilder) BuildManifestURL(ref reference.Named) (string, error) {
|
|||||||
tagOrDigest = v.Tag()
|
tagOrDigest = v.Tag()
|
||||||
case reference.Digested:
|
case reference.Digested:
|
||||||
tagOrDigest = v.Digest().String()
|
tagOrDigest = v.Digest().String()
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("reference must have a tag or digest")
|
||||||
}
|
}
|
||||||
|
|
||||||
manifestURL, err := route.URL("name", ref.Name(), "reference", tagOrDigest)
|
manifestURL, err := route.URL("name", ref.Name(), "reference", tagOrDigest)
|
||||||
|
|||||||
56
vendor/github.com/docker/distribution/registry/api/v2/urls_test.go
generated
vendored
56
vendor/github.com/docker/distribution/registry/api/v2/urls_test.go
generated
vendored
@@ -1,8 +1,10 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
@@ -11,35 +13,48 @@ import (
|
|||||||
type urlBuilderTestCase struct {
|
type urlBuilderTestCase struct {
|
||||||
description string
|
description string
|
||||||
expectedPath string
|
expectedPath string
|
||||||
|
expectedErr error
|
||||||
build func() (string, error)
|
build func() (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeURLBuilderTestCases(urlBuilder *URLBuilder) []urlBuilderTestCase {
|
func makeURLBuilderTestCases(urlBuilder *URLBuilder) []urlBuilderTestCase {
|
||||||
fooBarRef, _ := reference.ParseNamed("foo/bar")
|
fooBarRef, _ := reference.WithName("foo/bar")
|
||||||
return []urlBuilderTestCase{
|
return []urlBuilderTestCase{
|
||||||
{
|
{
|
||||||
description: "test base url",
|
description: "test base url",
|
||||||
expectedPath: "/v2/",
|
expectedPath: "/v2/",
|
||||||
|
expectedErr: nil,
|
||||||
build: urlBuilder.BuildBaseURL,
|
build: urlBuilder.BuildBaseURL,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "test tags url",
|
description: "test tags url",
|
||||||
expectedPath: "/v2/foo/bar/tags/list",
|
expectedPath: "/v2/foo/bar/tags/list",
|
||||||
|
expectedErr: nil,
|
||||||
build: func() (string, error) {
|
build: func() (string, error) {
|
||||||
return urlBuilder.BuildTagsURL(fooBarRef)
|
return urlBuilder.BuildTagsURL(fooBarRef)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "test manifest url",
|
description: "test manifest url tagged ref",
|
||||||
expectedPath: "/v2/foo/bar/manifests/tag",
|
expectedPath: "/v2/foo/bar/manifests/tag",
|
||||||
|
expectedErr: nil,
|
||||||
build: func() (string, error) {
|
build: func() (string, error) {
|
||||||
ref, _ := reference.WithTag(fooBarRef, "tag")
|
ref, _ := reference.WithTag(fooBarRef, "tag")
|
||||||
return urlBuilder.BuildManifestURL(ref)
|
return urlBuilder.BuildManifestURL(ref)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "test manifest url bare ref",
|
||||||
|
expectedPath: "",
|
||||||
|
expectedErr: fmt.Errorf("reference must have a tag or digest"),
|
||||||
|
build: func() (string, error) {
|
||||||
|
return urlBuilder.BuildManifestURL(fooBarRef)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "build blob url",
|
description: "build blob url",
|
||||||
expectedPath: "/v2/foo/bar/blobs/sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5",
|
expectedPath: "/v2/foo/bar/blobs/sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5",
|
||||||
|
expectedErr: nil,
|
||||||
build: func() (string, error) {
|
build: func() (string, error) {
|
||||||
ref, _ := reference.WithDigest(fooBarRef, "sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5")
|
ref, _ := reference.WithDigest(fooBarRef, "sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5")
|
||||||
return urlBuilder.BuildBlobURL(ref)
|
return urlBuilder.BuildBlobURL(ref)
|
||||||
@@ -48,6 +63,7 @@ func makeURLBuilderTestCases(urlBuilder *URLBuilder) []urlBuilderTestCase {
|
|||||||
{
|
{
|
||||||
description: "build blob upload url",
|
description: "build blob upload url",
|
||||||
expectedPath: "/v2/foo/bar/blobs/uploads/",
|
expectedPath: "/v2/foo/bar/blobs/uploads/",
|
||||||
|
expectedErr: nil,
|
||||||
build: func() (string, error) {
|
build: func() (string, error) {
|
||||||
return urlBuilder.BuildBlobUploadURL(fooBarRef)
|
return urlBuilder.BuildBlobUploadURL(fooBarRef)
|
||||||
},
|
},
|
||||||
@@ -55,6 +71,7 @@ func makeURLBuilderTestCases(urlBuilder *URLBuilder) []urlBuilderTestCase {
|
|||||||
{
|
{
|
||||||
description: "build blob upload url with digest and size",
|
description: "build blob upload url with digest and size",
|
||||||
expectedPath: "/v2/foo/bar/blobs/uploads/?digest=sha256%3A3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5&size=10000",
|
expectedPath: "/v2/foo/bar/blobs/uploads/?digest=sha256%3A3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5&size=10000",
|
||||||
|
expectedErr: nil,
|
||||||
build: func() (string, error) {
|
build: func() (string, error) {
|
||||||
return urlBuilder.BuildBlobUploadURL(fooBarRef, url.Values{
|
return urlBuilder.BuildBlobUploadURL(fooBarRef, url.Values{
|
||||||
"size": []string{"10000"},
|
"size": []string{"10000"},
|
||||||
@@ -65,6 +82,7 @@ func makeURLBuilderTestCases(urlBuilder *URLBuilder) []urlBuilderTestCase {
|
|||||||
{
|
{
|
||||||
description: "build blob upload chunk url",
|
description: "build blob upload chunk url",
|
||||||
expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part",
|
expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part",
|
||||||
|
expectedErr: nil,
|
||||||
build: func() (string, error) {
|
build: func() (string, error) {
|
||||||
return urlBuilder.BuildBlobUploadChunkURL(fooBarRef, "uuid-part")
|
return urlBuilder.BuildBlobUploadChunkURL(fooBarRef, "uuid-part")
|
||||||
},
|
},
|
||||||
@@ -72,6 +90,7 @@ func makeURLBuilderTestCases(urlBuilder *URLBuilder) []urlBuilderTestCase {
|
|||||||
{
|
{
|
||||||
description: "build blob upload chunk url with digest and size",
|
description: "build blob upload chunk url with digest and size",
|
||||||
expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part?digest=sha256%3A3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5&size=10000",
|
expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part?digest=sha256%3A3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5&size=10000",
|
||||||
|
expectedErr: nil,
|
||||||
build: func() (string, error) {
|
build: func() (string, error) {
|
||||||
return urlBuilder.BuildBlobUploadChunkURL(fooBarRef, "uuid-part", url.Values{
|
return urlBuilder.BuildBlobUploadChunkURL(fooBarRef, "uuid-part", url.Values{
|
||||||
"size": []string{"10000"},
|
"size": []string{"10000"},
|
||||||
@@ -101,9 +120,14 @@ func TestURLBuilder(t *testing.T) {
|
|||||||
|
|
||||||
for _, testCase := range makeURLBuilderTestCases(urlBuilder) {
|
for _, testCase := range makeURLBuilderTestCases(urlBuilder) {
|
||||||
url, err := testCase.build()
|
url, err := testCase.build()
|
||||||
if err != nil {
|
expectedErr := testCase.expectedErr
|
||||||
t.Fatalf("%s: error building url: %v", testCase.description, err)
|
if !reflect.DeepEqual(expectedErr, err) {
|
||||||
|
t.Fatalf("%s: Expecting %v but got error %v", testCase.description, expectedErr, err)
|
||||||
}
|
}
|
||||||
|
if expectedErr != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
expectedURL := testCase.expectedPath
|
expectedURL := testCase.expectedPath
|
||||||
if !relative {
|
if !relative {
|
||||||
expectedURL = root + expectedURL
|
expectedURL = root + expectedURL
|
||||||
@@ -136,8 +160,12 @@ func TestURLBuilderWithPrefix(t *testing.T) {
|
|||||||
|
|
||||||
for _, testCase := range makeURLBuilderTestCases(urlBuilder) {
|
for _, testCase := range makeURLBuilderTestCases(urlBuilder) {
|
||||||
url, err := testCase.build()
|
url, err := testCase.build()
|
||||||
if err != nil {
|
expectedErr := testCase.expectedErr
|
||||||
t.Fatalf("%s: error building url: %v", testCase.description, err)
|
if !reflect.DeepEqual(expectedErr, err) {
|
||||||
|
t.Fatalf("%s: Expecting %v but got error %v", testCase.description, expectedErr, err)
|
||||||
|
}
|
||||||
|
if expectedErr != nil {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedURL := testCase.expectedPath
|
expectedURL := testCase.expectedPath
|
||||||
@@ -383,8 +411,12 @@ func TestBuilderFromRequest(t *testing.T) {
|
|||||||
|
|
||||||
for _, testCase := range makeURLBuilderTestCases(builder) {
|
for _, testCase := range makeURLBuilderTestCases(builder) {
|
||||||
buildURL, err := testCase.build()
|
buildURL, err := testCase.build()
|
||||||
if err != nil {
|
expectedErr := testCase.expectedErr
|
||||||
t.Fatalf("[relative=%t, request=%q, case=%q]: error building url: %v", relative, tr.name, testCase.description, err)
|
if !reflect.DeepEqual(expectedErr, err) {
|
||||||
|
t.Fatalf("%s: Expecting %v but got error %v", testCase.description, expectedErr, err)
|
||||||
|
}
|
||||||
|
if expectedErr != nil {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedURL := testCase.expectedPath
|
expectedURL := testCase.expectedPath
|
||||||
@@ -452,8 +484,12 @@ func TestBuilderFromRequestWithPrefix(t *testing.T) {
|
|||||||
|
|
||||||
for _, testCase := range makeURLBuilderTestCases(builder) {
|
for _, testCase := range makeURLBuilderTestCases(builder) {
|
||||||
buildURL, err := testCase.build()
|
buildURL, err := testCase.build()
|
||||||
if err != nil {
|
expectedErr := testCase.expectedErr
|
||||||
t.Fatalf("%s: error building url: %v", testCase.description, err)
|
if !reflect.DeepEqual(expectedErr, err) {
|
||||||
|
t.Fatalf("%s: Expecting %v but got error %v", testCase.description, expectedErr, err)
|
||||||
|
}
|
||||||
|
if expectedErr != nil {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var expectedURL string
|
var expectedURL string
|
||||||
|
|||||||
21
vendor/github.com/docker/distribution/registry/auth/token/token_test.go
generated
vendored
21
vendor/github.com/docker/distribution/registry/auth/token/token_test.go
generated
vendored
@@ -454,6 +454,27 @@ func TestAccessController(t *testing.T) {
|
|||||||
if userInfo.Name != "foo" {
|
if userInfo.Name != "foo" {
|
||||||
t.Fatalf("expected user name %q, got %q", "foo", userInfo.Name)
|
t.Fatalf("expected user name %q, got %q", "foo", userInfo.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 5. Supply a token with full admin rights, which is represented as "*".
|
||||||
|
token, err = makeTestToken(
|
||||||
|
issuer, service,
|
||||||
|
[]*ResourceActions{{
|
||||||
|
Type: testAccess.Type,
|
||||||
|
Name: testAccess.Name,
|
||||||
|
Actions: []string{"*"},
|
||||||
|
}},
|
||||||
|
rootKeys[0], 1, time.Now(), time.Now().Add(5*time.Minute),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token.compactRaw()))
|
||||||
|
|
||||||
|
_, err = accessController.Authorized(ctx, testAccess)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("accessController returned unexpected error: %s", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This tests that newAccessController can handle PEM blocks in the certificate
|
// This tests that newAccessController can handle PEM blocks in the certificate
|
||||||
|
|||||||
4
vendor/github.com/docker/distribution/registry/client/auth/session.go
generated
vendored
4
vendor/github.com/docker/distribution/registry/client/auth/session.go
generated
vendored
@@ -155,7 +155,9 @@ type RepositoryScope struct {
|
|||||||
// using the scope grammar
|
// using the scope grammar
|
||||||
func (rs RepositoryScope) String() string {
|
func (rs RepositoryScope) String() string {
|
||||||
repoType := "repository"
|
repoType := "repository"
|
||||||
if rs.Class != "" {
|
// Keep existing format for image class to maintain backwards compatibility
|
||||||
|
// with authorization servers which do not support the expanded grammar.
|
||||||
|
if rs.Class != "" && rs.Class != "image" {
|
||||||
repoType = fmt.Sprintf("%s(%s)", repoType, rs.Class)
|
repoType = fmt.Sprintf("%s(%s)", repoType, rs.Class)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s:%s:%s", repoType, rs.Repository, strings.Join(rs.Actions, ","))
|
return fmt.Sprintf("%s:%s:%s", repoType, rs.Repository, strings.Join(rs.Actions, ","))
|
||||||
|
|||||||
10
vendor/github.com/docker/distribution/registry/client/repository.go
generated
vendored
10
vendor/github.com/docker/distribution/registry/client/repository.go
generated
vendored
@@ -15,12 +15,12 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/api/v2"
|
"github.com/docker/distribution/registry/api/v2"
|
||||||
"github.com/docker/distribution/registry/client/transport"
|
"github.com/docker/distribution/registry/client/transport"
|
||||||
"github.com/docker/distribution/registry/storage/cache"
|
"github.com/docker/distribution/registry/storage/cache"
|
||||||
"github.com/docker/distribution/registry/storage/cache/memory"
|
"github.com/docker/distribution/registry/storage/cache/memory"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Registry provides an interface for calling Repositories, which returns a catalog of repositories.
|
// Registry provides an interface for calling Repositories, which returns a catalog of repositories.
|
||||||
@@ -268,7 +268,7 @@ func descriptorFromResponse(response *http.Response) (distribution.Descriptor, e
|
|||||||
return desc, nil
|
return desc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
dgst, err := digest.ParseDigest(digestHeader)
|
dgst, err := digest.Parse(digestHeader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return distribution.Descriptor{}, err
|
return distribution.Descriptor{}, err
|
||||||
}
|
}
|
||||||
@@ -475,7 +475,7 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis
|
|||||||
return nil, distribution.ErrManifestNotModified
|
return nil, distribution.ErrManifestNotModified
|
||||||
} else if SuccessStatus(resp.StatusCode) {
|
} else if SuccessStatus(resp.StatusCode) {
|
||||||
if contentDgst != nil {
|
if contentDgst != nil {
|
||||||
dgst, err := digest.ParseDigest(resp.Header.Get("Docker-Content-Digest"))
|
dgst, err := digest.Parse(resp.Header.Get("Docker-Content-Digest"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
*contentDgst = dgst
|
*contentDgst = dgst
|
||||||
}
|
}
|
||||||
@@ -553,7 +553,7 @@ func (ms *manifests) Put(ctx context.Context, m distribution.Manifest, options .
|
|||||||
|
|
||||||
if SuccessStatus(resp.StatusCode) {
|
if SuccessStatus(resp.StatusCode) {
|
||||||
dgstHeader := resp.Header.Get("Docker-Content-Digest")
|
dgstHeader := resp.Header.Get("Docker-Content-Digest")
|
||||||
dgst, err := digest.ParseDigest(dgstHeader)
|
dgst, err := digest.Parse(dgstHeader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -661,7 +661,7 @@ func (bs *blobs) Put(ctx context.Context, mediaType string, p []byte) (distribut
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return distribution.Descriptor{}, err
|
return distribution.Descriptor{}, err
|
||||||
}
|
}
|
||||||
dgstr := digest.Canonical.New()
|
dgstr := digest.Canonical.Digester()
|
||||||
n, err := io.Copy(writer, io.TeeReader(bytes.NewReader(p), dgstr.Hash()))
|
n, err := io.Copy(writer, io.TeeReader(bytes.NewReader(p), dgstr.Hash()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return distribution.Descriptor{}, err
|
return distribution.Descriptor{}, err
|
||||||
|
|||||||
34
vendor/github.com/docker/distribution/registry/client/repository_test.go
generated
vendored
34
vendor/github.com/docker/distribution/registry/client/repository_test.go
generated
vendored
@@ -16,7 +16,6 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/manifest"
|
"github.com/docker/distribution/manifest"
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
@@ -25,6 +24,7 @@ import (
|
|||||||
"github.com/docker/distribution/testutil"
|
"github.com/docker/distribution/testutil"
|
||||||
"github.com/docker/distribution/uuid"
|
"github.com/docker/distribution/uuid"
|
||||||
"github.com/docker/libtrust"
|
"github.com/docker/libtrust"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testServer(rrm testutil.RequestResponseMap) (string, func()) {
|
func testServer(rrm testutil.RequestResponseMap) (string, func()) {
|
||||||
@@ -100,7 +100,7 @@ func addTestCatalog(route string, content []byte, link string, m *testutil.Reque
|
|||||||
func TestBlobDelete(t *testing.T) {
|
func TestBlobDelete(t *testing.T) {
|
||||||
dgst, _ := newRandomBlob(1024)
|
dgst, _ := newRandomBlob(1024)
|
||||||
var m testutil.RequestResponseMap
|
var m testutil.RequestResponseMap
|
||||||
repo, _ := reference.ParseNamed("test.example.com/repo1")
|
repo, _ := reference.WithName("test.example.com/repo1")
|
||||||
m = append(m, testutil.RequestResponseMapping{
|
m = append(m, testutil.RequestResponseMapping{
|
||||||
Request: testutil.Request{
|
Request: testutil.Request{
|
||||||
Method: "DELETE",
|
Method: "DELETE",
|
||||||
@@ -139,7 +139,7 @@ func TestBlobFetch(t *testing.T) {
|
|||||||
defer c()
|
defer c()
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
repo, _ := reference.ParseNamed("test.example.com/repo1")
|
repo, _ := reference.WithName("test.example.com/repo1")
|
||||||
r, err := NewRepository(ctx, repo, e, nil)
|
r, err := NewRepository(ctx, repo, e, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -160,7 +160,7 @@ func TestBlobFetch(t *testing.T) {
|
|||||||
func TestBlobExistsNoContentLength(t *testing.T) {
|
func TestBlobExistsNoContentLength(t *testing.T) {
|
||||||
var m testutil.RequestResponseMap
|
var m testutil.RequestResponseMap
|
||||||
|
|
||||||
repo, _ := reference.ParseNamed("biff")
|
repo, _ := reference.WithName("biff")
|
||||||
dgst, content := newRandomBlob(1024)
|
dgst, content := newRandomBlob(1024)
|
||||||
m = append(m, testutil.RequestResponseMapping{
|
m = append(m, testutil.RequestResponseMapping{
|
||||||
Request: testutil.Request{
|
Request: testutil.Request{
|
||||||
@@ -219,7 +219,7 @@ func TestBlobExists(t *testing.T) {
|
|||||||
defer c()
|
defer c()
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
repo, _ := reference.ParseNamed("test.example.com/repo1")
|
repo, _ := reference.WithName("test.example.com/repo1")
|
||||||
r, err := NewRepository(ctx, repo, e, nil)
|
r, err := NewRepository(ctx, repo, e, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -251,7 +251,7 @@ func TestBlobUploadChunked(t *testing.T) {
|
|||||||
b1[512:513],
|
b1[512:513],
|
||||||
b1[513:1024],
|
b1[513:1024],
|
||||||
}
|
}
|
||||||
repo, _ := reference.ParseNamed("test.example.com/uploadrepo")
|
repo, _ := reference.WithName("test.example.com/uploadrepo")
|
||||||
uuids := []string{uuid.Generate().String()}
|
uuids := []string{uuid.Generate().String()}
|
||||||
m = append(m, testutil.RequestResponseMapping{
|
m = append(m, testutil.RequestResponseMapping{
|
||||||
Request: testutil.Request{
|
Request: testutil.Request{
|
||||||
@@ -366,7 +366,7 @@ func TestBlobUploadChunked(t *testing.T) {
|
|||||||
func TestBlobUploadMonolithic(t *testing.T) {
|
func TestBlobUploadMonolithic(t *testing.T) {
|
||||||
dgst, b1 := newRandomBlob(1024)
|
dgst, b1 := newRandomBlob(1024)
|
||||||
var m testutil.RequestResponseMap
|
var m testutil.RequestResponseMap
|
||||||
repo, _ := reference.ParseNamed("test.example.com/uploadrepo")
|
repo, _ := reference.WithName("test.example.com/uploadrepo")
|
||||||
uploadID := uuid.Generate().String()
|
uploadID := uuid.Generate().String()
|
||||||
m = append(m, testutil.RequestResponseMapping{
|
m = append(m, testutil.RequestResponseMapping{
|
||||||
Request: testutil.Request{
|
Request: testutil.Request{
|
||||||
@@ -474,9 +474,9 @@ func TestBlobUploadMonolithic(t *testing.T) {
|
|||||||
func TestBlobMount(t *testing.T) {
|
func TestBlobMount(t *testing.T) {
|
||||||
dgst, content := newRandomBlob(1024)
|
dgst, content := newRandomBlob(1024)
|
||||||
var m testutil.RequestResponseMap
|
var m testutil.RequestResponseMap
|
||||||
repo, _ := reference.ParseNamed("test.example.com/uploadrepo")
|
repo, _ := reference.WithName("test.example.com/uploadrepo")
|
||||||
|
|
||||||
sourceRepo, _ := reference.ParseNamed("test.example.com/sourcerepo")
|
sourceRepo, _ := reference.WithName("test.example.com/sourcerepo")
|
||||||
canonicalRef, _ := reference.WithDigest(sourceRepo, dgst)
|
canonicalRef, _ := reference.WithDigest(sourceRepo, dgst)
|
||||||
|
|
||||||
m = append(m, testutil.RequestResponseMapping{
|
m = append(m, testutil.RequestResponseMapping{
|
||||||
@@ -678,7 +678,7 @@ func checkEqualManifest(m1, m2 *schema1.SignedManifest) error {
|
|||||||
|
|
||||||
func TestV1ManifestFetch(t *testing.T) {
|
func TestV1ManifestFetch(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
repo, _ := reference.ParseNamed("test.example.com/repo")
|
repo, _ := reference.WithName("test.example.com/repo")
|
||||||
m1, dgst, _ := newRandomSchemaV1Manifest(repo, "latest", 6)
|
m1, dgst, _ := newRandomSchemaV1Manifest(repo, "latest", 6)
|
||||||
var m testutil.RequestResponseMap
|
var m testutil.RequestResponseMap
|
||||||
_, pl, err := m1.Payload()
|
_, pl, err := m1.Payload()
|
||||||
@@ -755,7 +755,7 @@ func TestV1ManifestFetch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestManifestFetchWithEtag(t *testing.T) {
|
func TestManifestFetchWithEtag(t *testing.T) {
|
||||||
repo, _ := reference.ParseNamed("test.example.com/repo/by/tag")
|
repo, _ := reference.WithName("test.example.com/repo/by/tag")
|
||||||
_, d1, p1 := newRandomSchemaV1Manifest(repo, "latest", 6)
|
_, d1, p1 := newRandomSchemaV1Manifest(repo, "latest", 6)
|
||||||
var m testutil.RequestResponseMap
|
var m testutil.RequestResponseMap
|
||||||
addTestManifestWithEtag(repo, "latest", p1, &m, d1.String())
|
addTestManifestWithEtag(repo, "latest", p1, &m, d1.String())
|
||||||
@@ -785,7 +785,7 @@ func TestManifestFetchWithEtag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestManifestDelete(t *testing.T) {
|
func TestManifestDelete(t *testing.T) {
|
||||||
repo, _ := reference.ParseNamed("test.example.com/repo/delete")
|
repo, _ := reference.WithName("test.example.com/repo/delete")
|
||||||
_, dgst1, _ := newRandomSchemaV1Manifest(repo, "latest", 6)
|
_, dgst1, _ := newRandomSchemaV1Manifest(repo, "latest", 6)
|
||||||
_, dgst2, _ := newRandomSchemaV1Manifest(repo, "latest", 6)
|
_, dgst2, _ := newRandomSchemaV1Manifest(repo, "latest", 6)
|
||||||
var m testutil.RequestResponseMap
|
var m testutil.RequestResponseMap
|
||||||
@@ -825,7 +825,7 @@ func TestManifestDelete(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestManifestPut(t *testing.T) {
|
func TestManifestPut(t *testing.T) {
|
||||||
repo, _ := reference.ParseNamed("test.example.com/repo/delete")
|
repo, _ := reference.WithName("test.example.com/repo/delete")
|
||||||
m1, dgst, _ := newRandomSchemaV1Manifest(repo, "other", 6)
|
m1, dgst, _ := newRandomSchemaV1Manifest(repo, "other", 6)
|
||||||
|
|
||||||
_, payload, err := m1.Payload()
|
_, payload, err := m1.Payload()
|
||||||
@@ -890,7 +890,7 @@ func TestManifestPut(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestManifestTags(t *testing.T) {
|
func TestManifestTags(t *testing.T) {
|
||||||
repo, _ := reference.ParseNamed("test.example.com/repo/tags/list")
|
repo, _ := reference.WithName("test.example.com/repo/tags/list")
|
||||||
tagsList := []byte(strings.TrimSpace(`
|
tagsList := []byte(strings.TrimSpace(`
|
||||||
{
|
{
|
||||||
"name": "test.example.com/repo/tags/list",
|
"name": "test.example.com/repo/tags/list",
|
||||||
@@ -952,7 +952,7 @@ func TestManifestTags(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestObtainsErrorForMissingTag(t *testing.T) {
|
func TestObtainsErrorForMissingTag(t *testing.T) {
|
||||||
repo, _ := reference.ParseNamed("test.example.com/repo")
|
repo, _ := reference.WithName("test.example.com/repo")
|
||||||
|
|
||||||
var m testutil.RequestResponseMap
|
var m testutil.RequestResponseMap
|
||||||
var errors errcode.Errors
|
var errors errcode.Errors
|
||||||
@@ -998,7 +998,7 @@ func TestManifestTagsPaginated(t *testing.T) {
|
|||||||
s := httptest.NewServer(http.NotFoundHandler())
|
s := httptest.NewServer(http.NotFoundHandler())
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
repo, _ := reference.ParseNamed("test.example.com/repo/tags/list")
|
repo, _ := reference.WithName("test.example.com/repo/tags/list")
|
||||||
tagsList := []string{"tag1", "tag2", "funtag"}
|
tagsList := []string{"tag1", "tag2", "funtag"}
|
||||||
var m testutil.RequestResponseMap
|
var m testutil.RequestResponseMap
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
@@ -1067,7 +1067,7 @@ func TestManifestTagsPaginated(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestManifestUnauthorized(t *testing.T) {
|
func TestManifestUnauthorized(t *testing.T) {
|
||||||
repo, _ := reference.ParseNamed("test.example.com/repo")
|
repo, _ := reference.WithName("test.example.com/repo")
|
||||||
_, dgst, _ := newRandomSchemaV1Manifest(repo, "latest", 6)
|
_, dgst, _ := newRandomSchemaV1Manifest(repo, "latest", 6)
|
||||||
var m testutil.RequestResponseMap
|
var m testutil.RequestResponseMap
|
||||||
|
|
||||||
|
|||||||
160
vendor/github.com/docker/distribution/registry/handlers/api_test.go
generated
vendored
160
vendor/github.com/docker/distribution/registry/handlers/api_test.go
generated
vendored
@@ -3,6 +3,7 @@ package handlers
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -21,7 +22,6 @@ import (
|
|||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/configuration"
|
"github.com/docker/distribution/configuration"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/manifest"
|
"github.com/docker/distribution/manifest"
|
||||||
"github.com/docker/distribution/manifest/manifestlist"
|
"github.com/docker/distribution/manifest/manifestlist"
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
@@ -29,16 +29,24 @@ import (
|
|||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/api/errcode"
|
"github.com/docker/distribution/registry/api/errcode"
|
||||||
"github.com/docker/distribution/registry/api/v2"
|
"github.com/docker/distribution/registry/api/v2"
|
||||||
|
storagedriver "github.com/docker/distribution/registry/storage/driver"
|
||||||
|
"github.com/docker/distribution/registry/storage/driver/factory"
|
||||||
_ "github.com/docker/distribution/registry/storage/driver/testdriver"
|
_ "github.com/docker/distribution/registry/storage/driver/testdriver"
|
||||||
"github.com/docker/distribution/testutil"
|
"github.com/docker/distribution/testutil"
|
||||||
"github.com/docker/libtrust"
|
"github.com/docker/libtrust"
|
||||||
"github.com/gorilla/handlers"
|
"github.com/gorilla/handlers"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
var headerConfig = http.Header{
|
var headerConfig = http.Header{
|
||||||
"X-Content-Type-Options": []string{"nosniff"},
|
"X-Content-Type-Options": []string{"nosniff"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// digestSha256EmptyTar is the canonical sha256 digest of empty data
|
||||||
|
digestSha256EmptyTar = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||||
|
)
|
||||||
|
|
||||||
// TestCheckAPI hits the base endpoint (/v2/) ensures we return the specified
|
// TestCheckAPI hits the base endpoint (/v2/) ensures we return the specified
|
||||||
// 200 OK response.
|
// 200 OK response.
|
||||||
func TestCheckAPI(t *testing.T) {
|
func TestCheckAPI(t *testing.T) {
|
||||||
@@ -272,7 +280,7 @@ func makeBlobArgs(t *testing.T) blobArgs {
|
|||||||
layerFile: layerFile,
|
layerFile: layerFile,
|
||||||
layerDigest: layerDigest,
|
layerDigest: layerDigest,
|
||||||
}
|
}
|
||||||
args.imageName, _ = reference.ParseNamed("foo/bar")
|
args.imageName, _ = reference.WithName("foo/bar")
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,7 +522,7 @@ func testBlobAPI(t *testing.T, env *testEnv, args blobArgs) *testEnv {
|
|||||||
// Now, push just a chunk
|
// Now, push just a chunk
|
||||||
layerFile.Seek(0, 0)
|
layerFile.Seek(0, 0)
|
||||||
|
|
||||||
canonicalDigester := digest.Canonical.New()
|
canonicalDigester := digest.Canonical.Digester()
|
||||||
if _, err := io.Copy(canonicalDigester.Hash(), layerFile); err != nil {
|
if _, err := io.Copy(canonicalDigester.Hash(), layerFile); err != nil {
|
||||||
t.Fatalf("error copying to digest: %v", err)
|
t.Fatalf("error copying to digest: %v", err)
|
||||||
}
|
}
|
||||||
@@ -552,10 +560,7 @@ func testBlobAPI(t *testing.T, env *testEnv, args blobArgs) *testEnv {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Verify the body
|
// Verify the body
|
||||||
verifier, err := digest.NewDigestVerifier(layerDigest)
|
verifier := layerDigest.Verifier()
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error getting digest verifier: %s", err)
|
|
||||||
}
|
|
||||||
io.Copy(verifier, resp.Body)
|
io.Copy(verifier, resp.Body)
|
||||||
|
|
||||||
if !verifier.Verified() {
|
if !verifier.Verified() {
|
||||||
@@ -675,7 +680,7 @@ func testBlobDelete(t *testing.T, env *testEnv, args blobArgs) {
|
|||||||
pushLayer(t, env.builder, imageName, layerDigest, uploadURLBase, layerFile)
|
pushLayer(t, env.builder, imageName, layerDigest, uploadURLBase, layerFile)
|
||||||
|
|
||||||
layerFile.Seek(0, os.SEEK_SET)
|
layerFile.Seek(0, os.SEEK_SET)
|
||||||
canonicalDigester := digest.Canonical.New()
|
canonicalDigester := digest.Canonical.Digester()
|
||||||
if _, err := io.Copy(canonicalDigester.Hash(), layerFile); err != nil {
|
if _, err := io.Copy(canonicalDigester.Hash(), layerFile); err != nil {
|
||||||
t.Fatalf("error copying to digest: %v", err)
|
t.Fatalf("error copying to digest: %v", err)
|
||||||
}
|
}
|
||||||
@@ -700,7 +705,7 @@ func TestDeleteDisabled(t *testing.T) {
|
|||||||
env := newTestEnv(t, false)
|
env := newTestEnv(t, false)
|
||||||
defer env.Shutdown()
|
defer env.Shutdown()
|
||||||
|
|
||||||
imageName, _ := reference.ParseNamed("foo/bar")
|
imageName, _ := reference.WithName("foo/bar")
|
||||||
// "build" our layer file
|
// "build" our layer file
|
||||||
layerFile, layerDigest, err := testutil.CreateRandomTarFile()
|
layerFile, layerDigest, err := testutil.CreateRandomTarFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -727,7 +732,7 @@ func TestDeleteReadOnly(t *testing.T) {
|
|||||||
env := newTestEnv(t, true)
|
env := newTestEnv(t, true)
|
||||||
defer env.Shutdown()
|
defer env.Shutdown()
|
||||||
|
|
||||||
imageName, _ := reference.ParseNamed("foo/bar")
|
imageName, _ := reference.WithName("foo/bar")
|
||||||
// "build" our layer file
|
// "build" our layer file
|
||||||
layerFile, layerDigest, err := testutil.CreateRandomTarFile()
|
layerFile, layerDigest, err := testutil.CreateRandomTarFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -757,7 +762,7 @@ func TestStartPushReadOnly(t *testing.T) {
|
|||||||
defer env.Shutdown()
|
defer env.Shutdown()
|
||||||
env.app.readOnly = true
|
env.app.readOnly = true
|
||||||
|
|
||||||
imageName, _ := reference.ParseNamed("foo/bar")
|
imageName, _ := reference.WithName("foo/bar")
|
||||||
|
|
||||||
layerUploadURL, err := env.builder.BuildBlobUploadURL(imageName)
|
layerUploadURL, err := env.builder.BuildBlobUploadURL(imageName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -795,8 +800,8 @@ type manifestArgs struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestManifestAPI(t *testing.T) {
|
func TestManifestAPI(t *testing.T) {
|
||||||
schema1Repo, _ := reference.ParseNamed("foo/schema1")
|
schema1Repo, _ := reference.WithName("foo/schema1")
|
||||||
schema2Repo, _ := reference.ParseNamed("foo/schema2")
|
schema2Repo, _ := reference.WithName("foo/schema2")
|
||||||
|
|
||||||
deleteEnabled := false
|
deleteEnabled := false
|
||||||
env1 := newTestEnv(t, deleteEnabled)
|
env1 := newTestEnv(t, deleteEnabled)
|
||||||
@@ -813,9 +818,96 @@ func TestManifestAPI(t *testing.T) {
|
|||||||
testManifestAPIManifestList(t, env2, schema2Args)
|
testManifestAPIManifestList(t, env2, schema2Args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// storageManifestErrDriverFactory implements the factory.StorageDriverFactory interface.
|
||||||
|
type storageManifestErrDriverFactory struct{}
|
||||||
|
|
||||||
|
const (
|
||||||
|
repositoryWithManifestNotFound = "manifesttagnotfound"
|
||||||
|
repositoryWithManifestInvalidPath = "manifestinvalidpath"
|
||||||
|
repositoryWithManifestBadLink = "manifestbadlink"
|
||||||
|
repositoryWithGenericStorageError = "genericstorageerr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (factory *storageManifestErrDriverFactory) Create(parameters map[string]interface{}) (storagedriver.StorageDriver, error) {
|
||||||
|
// Initialize the mock driver
|
||||||
|
var errGenericStorage = errors.New("generic storage error")
|
||||||
|
return &mockErrorDriver{
|
||||||
|
returnErrs: []mockErrorMapping{
|
||||||
|
{
|
||||||
|
pathMatch: fmt.Sprintf("%s/_manifests/tags", repositoryWithManifestNotFound),
|
||||||
|
content: nil,
|
||||||
|
err: storagedriver.PathNotFoundError{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pathMatch: fmt.Sprintf("%s/_manifests/tags", repositoryWithManifestInvalidPath),
|
||||||
|
content: nil,
|
||||||
|
err: storagedriver.InvalidPathError{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pathMatch: fmt.Sprintf("%s/_manifests/tags", repositoryWithManifestBadLink),
|
||||||
|
content: []byte("this is a bad sha"),
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pathMatch: fmt.Sprintf("%s/_manifests/tags", repositoryWithGenericStorageError),
|
||||||
|
content: nil,
|
||||||
|
err: errGenericStorage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockErrorMapping struct {
|
||||||
|
pathMatch string
|
||||||
|
content []byte
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// mockErrorDriver implements StorageDriver to force storage error on manifest request
|
||||||
|
type mockErrorDriver struct {
|
||||||
|
storagedriver.StorageDriver
|
||||||
|
returnErrs []mockErrorMapping
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dr *mockErrorDriver) GetContent(ctx context.Context, path string) ([]byte, error) {
|
||||||
|
for _, returns := range dr.returnErrs {
|
||||||
|
if strings.Contains(path, returns.pathMatch) {
|
||||||
|
return returns.content, returns.err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("Unknown storage error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetManifestWithStorageError(t *testing.T) {
|
||||||
|
factory.Register("storagemanifesterror", &storageManifestErrDriverFactory{})
|
||||||
|
config := configuration.Configuration{
|
||||||
|
Storage: configuration.Storage{
|
||||||
|
"storagemanifesterror": configuration.Parameters{},
|
||||||
|
"maintenance": configuration.Parameters{"uploadpurging": map[interface{}]interface{}{
|
||||||
|
"enabled": false,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
config.HTTP.Headers = headerConfig
|
||||||
|
env1 := newTestEnvWithConfig(t, &config)
|
||||||
|
defer env1.Shutdown()
|
||||||
|
|
||||||
|
repo, _ := reference.WithName(repositoryWithManifestNotFound)
|
||||||
|
testManifestWithStorageError(t, env1, repo, http.StatusNotFound, v2.ErrorCodeManifestUnknown)
|
||||||
|
|
||||||
|
repo, _ = reference.WithName(repositoryWithGenericStorageError)
|
||||||
|
testManifestWithStorageError(t, env1, repo, http.StatusInternalServerError, errcode.ErrorCodeUnknown)
|
||||||
|
|
||||||
|
repo, _ = reference.WithName(repositoryWithManifestInvalidPath)
|
||||||
|
testManifestWithStorageError(t, env1, repo, http.StatusInternalServerError, errcode.ErrorCodeUnknown)
|
||||||
|
|
||||||
|
repo, _ = reference.WithName(repositoryWithManifestBadLink)
|
||||||
|
testManifestWithStorageError(t, env1, repo, http.StatusInternalServerError, errcode.ErrorCodeUnknown)
|
||||||
|
}
|
||||||
|
|
||||||
func TestManifestDelete(t *testing.T) {
|
func TestManifestDelete(t *testing.T) {
|
||||||
schema1Repo, _ := reference.ParseNamed("foo/schema1")
|
schema1Repo, _ := reference.WithName("foo/schema1")
|
||||||
schema2Repo, _ := reference.ParseNamed("foo/schema2")
|
schema2Repo, _ := reference.WithName("foo/schema2")
|
||||||
|
|
||||||
deleteEnabled := true
|
deleteEnabled := true
|
||||||
env := newTestEnv(t, deleteEnabled)
|
env := newTestEnv(t, deleteEnabled)
|
||||||
@@ -827,7 +919,7 @@ func TestManifestDelete(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestManifestDeleteDisabled(t *testing.T) {
|
func TestManifestDeleteDisabled(t *testing.T) {
|
||||||
schema1Repo, _ := reference.ParseNamed("foo/schema1")
|
schema1Repo, _ := reference.WithName("foo/schema1")
|
||||||
deleteEnabled := false
|
deleteEnabled := false
|
||||||
env := newTestEnv(t, deleteEnabled)
|
env := newTestEnv(t, deleteEnabled)
|
||||||
defer env.Shutdown()
|
defer env.Shutdown()
|
||||||
@@ -835,7 +927,7 @@ func TestManifestDeleteDisabled(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testManifestDeleteDisabled(t *testing.T, env *testEnv, imageName reference.Named) {
|
func testManifestDeleteDisabled(t *testing.T, env *testEnv, imageName reference.Named) {
|
||||||
ref, _ := reference.WithDigest(imageName, digest.DigestSha256EmptyTar)
|
ref, _ := reference.WithDigest(imageName, digestSha256EmptyTar)
|
||||||
manifestURL, err := env.builder.BuildManifestURL(ref)
|
manifestURL, err := env.builder.BuildManifestURL(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error getting manifest url: %v", err)
|
t.Fatalf("unexpected error getting manifest url: %v", err)
|
||||||
@@ -850,6 +942,26 @@ func testManifestDeleteDisabled(t *testing.T, env *testEnv, imageName reference.
|
|||||||
checkResponse(t, "status of disabled delete of manifest", resp, http.StatusMethodNotAllowed)
|
checkResponse(t, "status of disabled delete of manifest", resp, http.StatusMethodNotAllowed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testManifestWithStorageError(t *testing.T, env *testEnv, imageName reference.Named, expectedStatusCode int, expectedErrorCode errcode.ErrorCode) {
|
||||||
|
tag := "latest"
|
||||||
|
tagRef, _ := reference.WithTag(imageName, tag)
|
||||||
|
manifestURL, err := env.builder.BuildManifestURL(tagRef)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error getting manifest url: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------
|
||||||
|
// Attempt to fetch the manifest
|
||||||
|
resp, err := http.Get(manifestURL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error getting manifest: %v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
checkResponse(t, "getting non-existent manifest", resp, expectedStatusCode)
|
||||||
|
checkBodyHasErrorCodes(t, "getting non-existent manifest", resp, expectedErrorCode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func testManifestAPISchema1(t *testing.T, env *testEnv, imageName reference.Named) manifestArgs {
|
func testManifestAPISchema1(t *testing.T, env *testEnv, imageName reference.Named) manifestArgs {
|
||||||
tag := "thetag"
|
tag := "thetag"
|
||||||
args := manifestArgs{imageName: imageName}
|
args := manifestArgs{imageName: imageName}
|
||||||
@@ -1218,7 +1330,7 @@ func testManifestAPISchema2(t *testing.T, env *testEnv, imageName reference.Name
|
|||||||
Config: distribution.Descriptor{
|
Config: distribution.Descriptor{
|
||||||
Digest: "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b",
|
Digest: "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b",
|
||||||
Size: 3253,
|
Size: 3253,
|
||||||
MediaType: schema2.MediaTypeConfig,
|
MediaType: schema2.MediaTypeImageConfig,
|
||||||
},
|
},
|
||||||
Layers: []distribution.Descriptor{
|
Layers: []distribution.Descriptor{
|
||||||
{
|
{
|
||||||
@@ -2075,7 +2187,7 @@ func doPushLayer(t *testing.T, ub *v2.URLBuilder, name reference.Named, dgst dig
|
|||||||
|
|
||||||
// pushLayer pushes the layer content returning the url on success.
|
// pushLayer pushes the layer content returning the url on success.
|
||||||
func pushLayer(t *testing.T, ub *v2.URLBuilder, name reference.Named, dgst digest.Digest, uploadURLBase string, body io.Reader) string {
|
func pushLayer(t *testing.T, ub *v2.URLBuilder, name reference.Named, dgst digest.Digest, uploadURLBase string, body io.Reader) string {
|
||||||
digester := digest.Canonical.New()
|
digester := digest.Canonical.Digester()
|
||||||
|
|
||||||
resp, err := doPushLayer(t, ub, name, dgst, uploadURLBase, io.TeeReader(body, digester.Hash()))
|
resp, err := doPushLayer(t, ub, name, dgst, uploadURLBase, io.TeeReader(body, digester.Hash()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -2142,7 +2254,7 @@ func doPushChunk(t *testing.T, uploadURLBase string, body io.Reader) (*http.Resp
|
|||||||
|
|
||||||
uploadURL := u.String()
|
uploadURL := u.String()
|
||||||
|
|
||||||
digester := digest.Canonical.New()
|
digester := digest.Canonical.Digester()
|
||||||
|
|
||||||
req, err := http.NewRequest("PATCH", uploadURL, io.TeeReader(body, digester.Hash()))
|
req, err := http.NewRequest("PATCH", uploadURL, io.TeeReader(body, digester.Hash()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -2291,7 +2403,7 @@ func checkErr(t *testing.T, err error, msg string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createRepository(env *testEnv, t *testing.T, imageName string, tag string) digest.Digest {
|
func createRepository(env *testEnv, t *testing.T, imageName string, tag string) digest.Digest {
|
||||||
imageNameRef, err := reference.ParseNamed(imageName)
|
imageNameRef, err := reference.WithName(imageName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to parse reference: %v", err)
|
t.Fatalf("unable to parse reference: %v", err)
|
||||||
}
|
}
|
||||||
@@ -2362,7 +2474,7 @@ func TestRegistryAsCacheMutationAPIs(t *testing.T) {
|
|||||||
env := newTestEnvMirror(t, deleteEnabled)
|
env := newTestEnvMirror(t, deleteEnabled)
|
||||||
defer env.Shutdown()
|
defer env.Shutdown()
|
||||||
|
|
||||||
imageName, _ := reference.ParseNamed("foo/bar")
|
imageName, _ := reference.WithName("foo/bar")
|
||||||
tag := "latest"
|
tag := "latest"
|
||||||
tagRef, _ := reference.WithTag(imageName, tag)
|
tagRef, _ := reference.WithTag(imageName, tag)
|
||||||
manifestURL, err := env.builder.BuildManifestURL(tagRef)
|
manifestURL, err := env.builder.BuildManifestURL(tagRef)
|
||||||
@@ -2408,7 +2520,7 @@ func TestRegistryAsCacheMutationAPIs(t *testing.T) {
|
|||||||
checkResponse(t, fmt.Sprintf("starting layer push to cache %v", imageName), resp, errcode.ErrorCodeUnsupported.Descriptor().HTTPStatusCode)
|
checkResponse(t, fmt.Sprintf("starting layer push to cache %v", imageName), resp, errcode.ErrorCodeUnsupported.Descriptor().HTTPStatusCode)
|
||||||
|
|
||||||
// Blob Delete
|
// Blob Delete
|
||||||
ref, _ := reference.WithDigest(imageName, digest.DigestSha256EmptyTar)
|
ref, _ := reference.WithDigest(imageName, digestSha256EmptyTar)
|
||||||
blobURL, err := env.builder.BuildBlobURL(ref)
|
blobURL, err := env.builder.BuildBlobURL(ref)
|
||||||
resp, err = httpDelete(blobURL)
|
resp, err = httpDelete(blobURL)
|
||||||
checkResponse(t, "deleting blob from cache", resp, errcode.ErrorCodeUnsupported.Descriptor().HTTPStatusCode)
|
checkResponse(t, "deleting blob from cache", resp, errcode.ErrorCodeUnsupported.Descriptor().HTTPStatusCode)
|
||||||
@@ -2455,7 +2567,7 @@ func TestProxyManifestGetByTag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
truthConfig.HTTP.Headers = headerConfig
|
truthConfig.HTTP.Headers = headerConfig
|
||||||
|
|
||||||
imageName, _ := reference.ParseNamed("foo/bar")
|
imageName, _ := reference.WithName("foo/bar")
|
||||||
tag := "latest"
|
tag := "latest"
|
||||||
|
|
||||||
truthEnv := newTestEnvWithConfig(t, &truthConfig)
|
truthEnv := newTestEnvWithConfig(t, &truthConfig)
|
||||||
|
|||||||
41
vendor/github.com/docker/distribution/registry/handlers/app.go
generated
vendored
41
vendor/github.com/docker/distribution/registry/handlers/app.go
generated
vendored
@@ -100,7 +100,7 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
|||||||
app.register(v2.RouteNameBase, func(ctx *Context, r *http.Request) http.Handler {
|
app.register(v2.RouteNameBase, func(ctx *Context, r *http.Request) http.Handler {
|
||||||
return http.HandlerFunc(apiBase)
|
return http.HandlerFunc(apiBase)
|
||||||
})
|
})
|
||||||
app.register(v2.RouteNameManifest, imageManifestDispatcher)
|
app.register(v2.RouteNameManifest, manifestDispatcher)
|
||||||
app.register(v2.RouteNameCatalog, catalogDispatcher)
|
app.register(v2.RouteNameCatalog, catalogDispatcher)
|
||||||
app.register(v2.RouteNameTags, tagsDispatcher)
|
app.register(v2.RouteNameTags, tagsDispatcher)
|
||||||
app.register(v2.RouteNameBlob, blobDispatcher)
|
app.register(v2.RouteNameBlob, blobDispatcher)
|
||||||
@@ -213,6 +213,10 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
|||||||
options = append(options, storage.EnableRedirect)
|
options = append(options, storage.EnableRedirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !config.Validation.Enabled {
|
||||||
|
config.Validation.Enabled = !config.Validation.Disabled
|
||||||
|
}
|
||||||
|
|
||||||
// configure validation
|
// configure validation
|
||||||
if config.Validation.Enabled {
|
if config.Validation.Enabled {
|
||||||
if len(config.Validation.Manifests.URLs.Allow) == 0 && len(config.Validation.Manifests.URLs.Deny) == 0 {
|
if len(config.Validation.Manifests.URLs.Allow) == 0 && len(config.Validation.Manifests.URLs.Deny) == 0 {
|
||||||
@@ -592,24 +596,19 @@ func (app *App) configureSecret(configuration *configuration.Configuration) {
|
|||||||
func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close() // ensure that request body is always closed.
|
defer r.Body.Close() // ensure that request body is always closed.
|
||||||
|
|
||||||
// Instantiate an http context here so we can track the error codes
|
// Prepare the context with our own little decorations.
|
||||||
// returned by the request router.
|
ctx := r.Context()
|
||||||
ctx := defaultContextManager.context(app, w, r)
|
ctx = ctxu.WithRequest(ctx, r)
|
||||||
|
ctx, w = ctxu.WithResponseWriter(ctx, w)
|
||||||
|
ctx = ctxu.WithLogger(ctx, ctxu.GetRequestLogger(ctx))
|
||||||
|
r = r.WithContext(ctx)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
status, ok := ctx.Value("http.response.status").(int)
|
status, ok := ctx.Value("http.response.status").(int)
|
||||||
if ok && status >= 200 && status <= 399 {
|
if ok && status >= 200 && status <= 399 {
|
||||||
ctxu.GetResponseLogger(ctx).Infof("response completed")
|
ctxu.GetResponseLogger(r.Context()).Infof("response completed")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
defer defaultContextManager.release(ctx)
|
|
||||||
|
|
||||||
// NOTE(stevvooe): Total hack to get instrumented responsewriter from context.
|
|
||||||
var err error
|
|
||||||
w, err = ctxu.GetResponseWriter(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctxu.GetLogger(ctx).Warnf("response writer not found in context")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a header with the Docker Distribution API Version for all responses.
|
// Set a header with the Docker Distribution API Version for all responses.
|
||||||
w.Header().Add("Docker-Distribution-API-Version", "registry/2.0")
|
w.Header().Add("Docker-Distribution-API-Version", "registry/2.0")
|
||||||
@@ -645,8 +644,11 @@ func (app *App) dispatcher(dispatch dispatchFunc) http.Handler {
|
|||||||
// Add username to request logging
|
// Add username to request logging
|
||||||
context.Context = ctxu.WithLogger(context.Context, ctxu.GetLogger(context.Context, auth.UserNameKey))
|
context.Context = ctxu.WithLogger(context.Context, ctxu.GetLogger(context.Context, auth.UserNameKey))
|
||||||
|
|
||||||
|
// sync up context on the request.
|
||||||
|
r = r.WithContext(context)
|
||||||
|
|
||||||
if app.nameRequired(r) {
|
if app.nameRequired(r) {
|
||||||
nameRef, err := reference.ParseNamed(getName(context))
|
nameRef, err := reference.WithName(getName(context))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctxu.GetLogger(context).Errorf("error parsing reference from context: %v", err)
|
ctxu.GetLogger(context).Errorf("error parsing reference from context: %v", err)
|
||||||
context.Errors = append(context.Errors, distribution.ErrRepositoryNameInvalid{
|
context.Errors = append(context.Errors, distribution.ErrRepositoryNameInvalid{
|
||||||
@@ -752,7 +754,7 @@ func (app *App) logError(context context.Context, errors errcode.Errors) {
|
|||||||
// context constructs the context object for the application. This only be
|
// context constructs the context object for the application. This only be
|
||||||
// called once per request.
|
// called once per request.
|
||||||
func (app *App) context(w http.ResponseWriter, r *http.Request) *Context {
|
func (app *App) context(w http.ResponseWriter, r *http.Request) *Context {
|
||||||
ctx := defaultContextManager.context(app, w, r)
|
ctx := r.Context()
|
||||||
ctx = ctxu.WithVars(ctx, r)
|
ctx = ctxu.WithVars(ctx, r)
|
||||||
ctx = ctxu.WithLogger(ctx, ctxu.GetLogger(ctx,
|
ctx = ctxu.WithLogger(ctx, ctxu.GetLogger(ctx,
|
||||||
"vars.name",
|
"vars.name",
|
||||||
@@ -857,8 +859,11 @@ func (app *App) eventBridge(ctx *Context, r *http.Request) notifications.Listene
|
|||||||
// nameRequired returns true if the route requires a name.
|
// nameRequired returns true if the route requires a name.
|
||||||
func (app *App) nameRequired(r *http.Request) bool {
|
func (app *App) nameRequired(r *http.Request) bool {
|
||||||
route := mux.CurrentRoute(r)
|
route := mux.CurrentRoute(r)
|
||||||
|
if route == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
routeName := route.GetName()
|
routeName := route.GetName()
|
||||||
return route == nil || (routeName != v2.RouteNameBase && routeName != v2.RouteNameCatalog)
|
return routeName != v2.RouteNameBase && routeName != v2.RouteNameCatalog
|
||||||
}
|
}
|
||||||
|
|
||||||
// apiBase implements a simple yes-man for doing overall checks against the
|
// apiBase implements a simple yes-man for doing overall checks against the
|
||||||
@@ -897,12 +902,10 @@ func appendAccessRecords(records []auth.Access, method string, repo string) []au
|
|||||||
Action: "push",
|
Action: "push",
|
||||||
})
|
})
|
||||||
case "DELETE":
|
case "DELETE":
|
||||||
// DELETE access requires full admin rights, which is represented
|
|
||||||
// as "*". This may not be ideal.
|
|
||||||
records = append(records,
|
records = append(records,
|
||||||
auth.Access{
|
auth.Access{
|
||||||
Resource: resource,
|
Resource: resource,
|
||||||
Action: "*",
|
Action: "delete",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return records
|
return records
|
||||||
|
|||||||
6
vendor/github.com/docker/distribution/registry/handlers/app_test.go
generated
vendored
6
vendor/github.com/docker/distribution/registry/handlers/app_test.go
generated
vendored
@@ -229,9 +229,9 @@ func TestAppendAccessRecords(t *testing.T) {
|
|||||||
Resource: expectedResource,
|
Resource: expectedResource,
|
||||||
Action: "push",
|
Action: "push",
|
||||||
}
|
}
|
||||||
expectedAllRecord := auth.Access{
|
expectedDeleteRecord := auth.Access{
|
||||||
Resource: expectedResource,
|
Resource: expectedResource,
|
||||||
Action: "*",
|
Action: "delete",
|
||||||
}
|
}
|
||||||
|
|
||||||
records := []auth.Access{}
|
records := []auth.Access{}
|
||||||
@@ -271,7 +271,7 @@ func TestAppendAccessRecords(t *testing.T) {
|
|||||||
|
|
||||||
records = []auth.Access{}
|
records = []auth.Access{}
|
||||||
result = appendAccessRecords(records, "DELETE", repo)
|
result = appendAccessRecords(records, "DELETE", repo)
|
||||||
expectedResult = []auth.Access{expectedAllRecord}
|
expectedResult = []auth.Access{expectedDeleteRecord}
|
||||||
if ok := reflect.DeepEqual(result, expectedResult); !ok {
|
if ok := reflect.DeepEqual(result, expectedResult); !ok {
|
||||||
t.Fatalf("Actual access record differs from expected")
|
t.Fatalf("Actual access record differs from expected")
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/registry/handlers/blob.go
generated
vendored
2
vendor/github.com/docker/distribution/registry/handlers/blob.go
generated
vendored
@@ -5,10 +5,10 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/registry/api/errcode"
|
"github.com/docker/distribution/registry/api/errcode"
|
||||||
"github.com/docker/distribution/registry/api/v2"
|
"github.com/docker/distribution/registry/api/v2"
|
||||||
"github.com/gorilla/handlers"
|
"github.com/gorilla/handlers"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// blobDispatcher uses the request context to build a blobHandler.
|
// blobDispatcher uses the request context to build a blobHandler.
|
||||||
|
|||||||
8
vendor/github.com/docker/distribution/registry/handlers/blobupload.go
generated
vendored
8
vendor/github.com/docker/distribution/registry/handlers/blobupload.go
generated
vendored
@@ -7,12 +7,12 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
ctxu "github.com/docker/distribution/context"
|
ctxu "github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/api/errcode"
|
"github.com/docker/distribution/registry/api/errcode"
|
||||||
"github.com/docker/distribution/registry/api/v2"
|
"github.com/docker/distribution/registry/api/v2"
|
||||||
"github.com/docker/distribution/registry/storage"
|
"github.com/docker/distribution/registry/storage"
|
||||||
"github.com/gorilla/handlers"
|
"github.com/gorilla/handlers"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// blobUploadDispatcher constructs and returns the blob upload handler for the
|
// blobUploadDispatcher constructs and returns the blob upload handler for the
|
||||||
@@ -211,7 +211,7 @@ func (buh *blobUploadHandler) PutBlobUploadComplete(w http.ResponseWriter, r *ht
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dgst, err := digest.ParseDigest(dgstStr)
|
dgst, err := digest.Parse(dgstStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// no digest? return error, but allow retry.
|
// no digest? return error, but allow retry.
|
||||||
buh.Errors = append(buh.Errors, v2.ErrorCodeDigestInvalid.WithDetail("digest parsing failed"))
|
buh.Errors = append(buh.Errors, v2.ErrorCodeDigestInvalid.WithDetail("digest parsing failed"))
|
||||||
@@ -329,12 +329,12 @@ func (buh *blobUploadHandler) blobUploadResponse(w http.ResponseWriter, r *http.
|
|||||||
// successful, the blob is linked into the blob store and 201 Created is
|
// successful, the blob is linked into the blob store and 201 Created is
|
||||||
// returned with the canonical url of the blob.
|
// returned with the canonical url of the blob.
|
||||||
func (buh *blobUploadHandler) createBlobMountOption(fromRepo, mountDigest string) (distribution.BlobCreateOption, error) {
|
func (buh *blobUploadHandler) createBlobMountOption(fromRepo, mountDigest string) (distribution.BlobCreateOption, error) {
|
||||||
dgst, err := digest.ParseDigest(mountDigest)
|
dgst, err := digest.Parse(mountDigest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ref, err := reference.ParseNamed(fromRepo)
|
ref, err := reference.WithName(fromRepo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
64
vendor/github.com/docker/distribution/registry/handlers/context.go
generated
vendored
64
vendor/github.com/docker/distribution/registry/handlers/context.go
generated
vendored
@@ -3,14 +3,13 @@ package handlers
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
ctxu "github.com/docker/distribution/context"
|
ctxu "github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/registry/api/errcode"
|
"github.com/docker/distribution/registry/api/errcode"
|
||||||
"github.com/docker/distribution/registry/api/v2"
|
"github.com/docker/distribution/registry/api/v2"
|
||||||
"github.com/docker/distribution/registry/auth"
|
"github.com/docker/distribution/registry/auth"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -62,7 +61,7 @@ func getDigest(ctx context.Context) (dgst digest.Digest, err error) {
|
|||||||
return "", errDigestNotAvailable
|
return "", errDigestNotAvailable
|
||||||
}
|
}
|
||||||
|
|
||||||
d, err := digest.ParseDigest(dgstStr)
|
d, err := digest.Parse(dgstStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctxu.GetLogger(ctx).Errorf("error parsing digest=%q: %v", dgstStr, err)
|
ctxu.GetLogger(ctx).Errorf("error parsing digest=%q: %v", dgstStr, err)
|
||||||
return "", err
|
return "", err
|
||||||
@@ -91,62 +90,3 @@ func getUserName(ctx context.Context, r *http.Request) string {
|
|||||||
|
|
||||||
return username
|
return username
|
||||||
}
|
}
|
||||||
|
|
||||||
// contextManager allows us to associate net/context.Context instances with a
|
|
||||||
// request, based on the memory identity of http.Request. This prepares http-
|
|
||||||
// level context, which is not application specific. If this is called,
|
|
||||||
// (*contextManager).release must be called on the context when the request is
|
|
||||||
// completed.
|
|
||||||
//
|
|
||||||
// Providing this circumvents a lot of necessity for dispatchers with the
|
|
||||||
// benefit of instantiating the request context much earlier.
|
|
||||||
//
|
|
||||||
// TODO(stevvooe): Consider making this facility a part of the context package.
|
|
||||||
type contextManager struct {
|
|
||||||
contexts map[*http.Request]context.Context
|
|
||||||
mu sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultContextManager is just a global instance to register request contexts.
|
|
||||||
var defaultContextManager = newContextManager()
|
|
||||||
|
|
||||||
func newContextManager() *contextManager {
|
|
||||||
return &contextManager{
|
|
||||||
contexts: make(map[*http.Request]context.Context),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// context either returns a new context or looks it up in the manager.
|
|
||||||
func (cm *contextManager) context(parent context.Context, w http.ResponseWriter, r *http.Request) context.Context {
|
|
||||||
cm.mu.Lock()
|
|
||||||
defer cm.mu.Unlock()
|
|
||||||
|
|
||||||
ctx, ok := cm.contexts[r]
|
|
||||||
if ok {
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
if parent == nil {
|
|
||||||
parent = ctxu.Background()
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = ctxu.WithRequest(parent, r)
|
|
||||||
ctx, w = ctxu.WithResponseWriter(ctx, w)
|
|
||||||
ctx = ctxu.WithLogger(ctx, ctxu.GetRequestLogger(ctx))
|
|
||||||
cm.contexts[r] = ctx
|
|
||||||
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
// releases frees any associated with resources from request.
|
|
||||||
func (cm *contextManager) release(ctx context.Context) {
|
|
||||||
cm.mu.Lock()
|
|
||||||
defer cm.mu.Unlock()
|
|
||||||
|
|
||||||
r, err := ctxu.GetRequest(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctxu.GetLogger(ctx).Errorf("no request found in context during release")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
delete(cm.contexts, r)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
ctxu "github.com/docker/distribution/context"
|
ctxu "github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/manifest/manifestlist"
|
"github.com/docker/distribution/manifest/manifestlist"
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
"github.com/docker/distribution/manifest/schema2"
|
"github.com/docker/distribution/manifest/schema2"
|
||||||
@@ -17,6 +16,7 @@ import (
|
|||||||
"github.com/docker/distribution/registry/api/v2"
|
"github.com/docker/distribution/registry/api/v2"
|
||||||
"github.com/docker/distribution/registry/auth"
|
"github.com/docker/distribution/registry/auth"
|
||||||
"github.com/gorilla/handlers"
|
"github.com/gorilla/handlers"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// These constants determine which architecture and OS to choose from a
|
// These constants determine which architecture and OS to choose from a
|
||||||
@@ -26,36 +26,36 @@ const (
|
|||||||
defaultOS = "linux"
|
defaultOS = "linux"
|
||||||
)
|
)
|
||||||
|
|
||||||
// imageManifestDispatcher takes the request context and builds the
|
// manifestDispatcher takes the request context and builds the
|
||||||
// appropriate handler for handling image manifest requests.
|
// appropriate handler for handling manifest requests.
|
||||||
func imageManifestDispatcher(ctx *Context, r *http.Request) http.Handler {
|
func manifestDispatcher(ctx *Context, r *http.Request) http.Handler {
|
||||||
imageManifestHandler := &imageManifestHandler{
|
manifestHandler := &manifestHandler{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
}
|
}
|
||||||
reference := getReference(ctx)
|
reference := getReference(ctx)
|
||||||
dgst, err := digest.ParseDigest(reference)
|
dgst, err := digest.Parse(reference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// We just have a tag
|
// We just have a tag
|
||||||
imageManifestHandler.Tag = reference
|
manifestHandler.Tag = reference
|
||||||
} else {
|
} else {
|
||||||
imageManifestHandler.Digest = dgst
|
manifestHandler.Digest = dgst
|
||||||
}
|
}
|
||||||
|
|
||||||
mhandler := handlers.MethodHandler{
|
mhandler := handlers.MethodHandler{
|
||||||
"GET": http.HandlerFunc(imageManifestHandler.GetImageManifest),
|
"GET": http.HandlerFunc(manifestHandler.GetManifest),
|
||||||
"HEAD": http.HandlerFunc(imageManifestHandler.GetImageManifest),
|
"HEAD": http.HandlerFunc(manifestHandler.GetManifest),
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.readOnly {
|
if !ctx.readOnly {
|
||||||
mhandler["PUT"] = http.HandlerFunc(imageManifestHandler.PutImageManifest)
|
mhandler["PUT"] = http.HandlerFunc(manifestHandler.PutManifest)
|
||||||
mhandler["DELETE"] = http.HandlerFunc(imageManifestHandler.DeleteImageManifest)
|
mhandler["DELETE"] = http.HandlerFunc(manifestHandler.DeleteManifest)
|
||||||
}
|
}
|
||||||
|
|
||||||
return mhandler
|
return mhandler
|
||||||
}
|
}
|
||||||
|
|
||||||
// imageManifestHandler handles http operations on image manifests.
|
// manifestHandler handles http operations on image manifests.
|
||||||
type imageManifestHandler struct {
|
type manifestHandler struct {
|
||||||
*Context
|
*Context
|
||||||
|
|
||||||
// One of tag or digest gets set, depending on what is present in context.
|
// One of tag or digest gets set, depending on what is present in context.
|
||||||
@@ -63,8 +63,8 @@ type imageManifestHandler struct {
|
|||||||
Digest digest.Digest
|
Digest digest.Digest
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetImageManifest fetches the image manifest from the storage backend, if it exists.
|
// GetManifest fetches the image manifest from the storage backend, if it exists.
|
||||||
func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http.Request) {
|
func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) {
|
||||||
ctxu.GetLogger(imh).Debug("GetImageManifest")
|
ctxu.GetLogger(imh).Debug("GetImageManifest")
|
||||||
manifests, err := imh.Repository.Manifests(imh)
|
manifests, err := imh.Repository.Manifests(imh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -77,7 +77,11 @@ func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http
|
|||||||
tags := imh.Repository.Tags(imh)
|
tags := imh.Repository.Tags(imh)
|
||||||
desc, err := tags.Get(imh, imh.Tag)
|
desc, err := tags.Get(imh, imh.Tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if _, ok := err.(distribution.ErrTagUnknown); ok {
|
||||||
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err))
|
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err))
|
||||||
|
} else {
|
||||||
|
imh.Errors = append(imh.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
imh.Digest = desc.Digest
|
imh.Digest = desc.Digest
|
||||||
@@ -94,7 +98,11 @@ func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http
|
|||||||
}
|
}
|
||||||
manifest, err = manifests.Get(imh, imh.Digest, options...)
|
manifest, err = manifests.Get(imh, imh.Digest, options...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if _, ok := err.(distribution.ErrManifestUnknownRevision); ok {
|
||||||
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err))
|
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err))
|
||||||
|
} else {
|
||||||
|
imh.Errors = append(imh.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +169,11 @@ func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http
|
|||||||
|
|
||||||
manifest, err = manifests.Get(imh, manifestDigest)
|
manifest, err = manifests.Get(imh, manifestDigest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if _, ok := err.(distribution.ErrManifestUnknownRevision); ok {
|
||||||
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err))
|
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err))
|
||||||
|
} else {
|
||||||
|
imh.Errors = append(imh.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +183,8 @@ func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
imh.Digest = manifestDigest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,12 +200,16 @@ func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http
|
|||||||
w.Write(p)
|
w.Write(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imh *imageManifestHandler) convertSchema2Manifest(schema2Manifest *schema2.DeserializedManifest) (distribution.Manifest, error) {
|
func (imh *manifestHandler) convertSchema2Manifest(schema2Manifest *schema2.DeserializedManifest) (distribution.Manifest, error) {
|
||||||
targetDescriptor := schema2Manifest.Target()
|
targetDescriptor := schema2Manifest.Target()
|
||||||
blobs := imh.Repository.Blobs(imh)
|
blobs := imh.Repository.Blobs(imh)
|
||||||
configJSON, err := blobs.Get(imh, targetDescriptor.Digest)
|
configJSON, err := blobs.Get(imh, targetDescriptor.Digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == distribution.ErrBlobUnknown {
|
||||||
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestInvalid.WithDetail(err))
|
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestInvalid.WithDetail(err))
|
||||||
|
} else {
|
||||||
|
imh.Errors = append(imh.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,8 +249,8 @@ func etagMatch(r *http.Request, etag string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutImageManifest validates and stores an image in the registry.
|
// PutManifest validates and stores a manifest in the registry.
|
||||||
func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http.Request) {
|
func (imh *manifestHandler) PutManifest(w http.ResponseWriter, r *http.Request) {
|
||||||
ctxu.GetLogger(imh).Debug("PutImageManifest")
|
ctxu.GetLogger(imh).Debug("PutImageManifest")
|
||||||
manifests, err := imh.Repository.Manifests(imh)
|
manifests, err := imh.Repository.Manifests(imh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -348,7 +366,7 @@ func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http
|
|||||||
|
|
||||||
// applyResourcePolicy checks whether the resource class matches what has
|
// applyResourcePolicy checks whether the resource class matches what has
|
||||||
// been authorized and allowed by the policy configuration.
|
// been authorized and allowed by the policy configuration.
|
||||||
func (imh *imageManifestHandler) applyResourcePolicy(manifest distribution.Manifest) error {
|
func (imh *manifestHandler) applyResourcePolicy(manifest distribution.Manifest) error {
|
||||||
allowedClasses := imh.App.Config.Policy.Repository.Classes
|
allowedClasses := imh.App.Config.Policy.Repository.Classes
|
||||||
if len(allowedClasses) == 0 {
|
if len(allowedClasses) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@@ -360,7 +378,7 @@ func (imh *imageManifestHandler) applyResourcePolicy(manifest distribution.Manif
|
|||||||
class = "image"
|
class = "image"
|
||||||
case *schema2.DeserializedManifest:
|
case *schema2.DeserializedManifest:
|
||||||
switch m.Config.MediaType {
|
switch m.Config.MediaType {
|
||||||
case schema2.MediaTypeConfig:
|
case schema2.MediaTypeImageConfig:
|
||||||
class = "image"
|
class = "image"
|
||||||
case schema2.MediaTypePluginConfig:
|
case schema2.MediaTypePluginConfig:
|
||||||
class = "plugin"
|
class = "plugin"
|
||||||
@@ -413,8 +431,8 @@ func (imh *imageManifestHandler) applyResourcePolicy(manifest distribution.Manif
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteImageManifest removes the manifest with the given digest from the registry.
|
// DeleteManifest removes the manifest with the given digest from the registry.
|
||||||
func (imh *imageManifestHandler) DeleteImageManifest(w http.ResponseWriter, r *http.Request) {
|
func (imh *manifestHandler) DeleteManifest(w http.ResponseWriter, r *http.Request) {
|
||||||
ctxu.GetLogger(imh).Debug("DeleteImageManifest")
|
ctxu.GetLogger(imh).Debug("DeleteImageManifest")
|
||||||
|
|
||||||
manifests, err := imh.Repository.Manifests(imh)
|
manifests, err := imh.Repository.Manifests(imh)
|
||||||
2
vendor/github.com/docker/distribution/registry/proxy/proxyblobstore.go
generated
vendored
2
vendor/github.com/docker/distribution/registry/proxy/proxyblobstore.go
generated
vendored
@@ -9,9 +9,9 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/proxy/scheduler"
|
"github.com/docker/distribution/registry/proxy/scheduler"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// todo(richardscothern): from cache control header or config file
|
// todo(richardscothern): from cache control header or config file
|
||||||
|
|||||||
4
vendor/github.com/docker/distribution/registry/proxy/proxyblobstore_test.go
generated
vendored
4
vendor/github.com/docker/distribution/registry/proxy/proxyblobstore_test.go
generated
vendored
@@ -11,13 +11,13 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/proxy/scheduler"
|
"github.com/docker/distribution/registry/proxy/scheduler"
|
||||||
"github.com/docker/distribution/registry/storage"
|
"github.com/docker/distribution/registry/storage"
|
||||||
"github.com/docker/distribution/registry/storage/cache/memory"
|
"github.com/docker/distribution/registry/storage/cache/memory"
|
||||||
"github.com/docker/distribution/registry/storage/driver/filesystem"
|
"github.com/docker/distribution/registry/storage/driver/filesystem"
|
||||||
"github.com/docker/distribution/registry/storage/driver/inmemory"
|
"github.com/docker/distribution/registry/storage/driver/inmemory"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
var sbsMu sync.Mutex
|
var sbsMu sync.Mutex
|
||||||
@@ -115,7 +115,7 @@ func (te *testEnv) RemoteStats() *map[string]int {
|
|||||||
|
|
||||||
// Populate remote store and record the digests
|
// Populate remote store and record the digests
|
||||||
func makeTestEnv(t *testing.T, name string) *testEnv {
|
func makeTestEnv(t *testing.T, name string) *testEnv {
|
||||||
nameRef, err := reference.ParseNamed(name)
|
nameRef, err := reference.WithName(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to parse reference: %s", err)
|
t.Fatalf("unable to parse reference: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/registry/proxy/proxymanifeststore.go
generated
vendored
2
vendor/github.com/docker/distribution/registry/proxy/proxymanifeststore.go
generated
vendored
@@ -5,9 +5,9 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/proxy/scheduler"
|
"github.com/docker/distribution/registry/proxy/scheduler"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// todo(richardscothern): from cache control header or config
|
// todo(richardscothern): from cache control header or config
|
||||||
|
|||||||
4
vendor/github.com/docker/distribution/registry/proxy/proxymanifeststore_test.go
generated
vendored
4
vendor/github.com/docker/distribution/registry/proxy/proxymanifeststore_test.go
generated
vendored
@@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/manifest"
|
"github.com/docker/distribution/manifest"
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
@@ -19,6 +18,7 @@ import (
|
|||||||
"github.com/docker/distribution/registry/storage/driver/inmemory"
|
"github.com/docker/distribution/registry/storage/driver/inmemory"
|
||||||
"github.com/docker/distribution/testutil"
|
"github.com/docker/distribution/testutil"
|
||||||
"github.com/docker/libtrust"
|
"github.com/docker/libtrust"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
type statsManifest struct {
|
type statsManifest struct {
|
||||||
@@ -83,7 +83,7 @@ func (m *mockChallenger) challengeManager() challenge.Manager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestEnv {
|
func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestEnv {
|
||||||
nameRef, err := reference.ParseNamed(name)
|
nameRef, err := reference.WithName(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to parse reference: %s", err)
|
t.Fatalf("unable to parse reference: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/registry/registry.go
generated
vendored
2
vendor/github.com/docker/distribution/registry/registry.go
generated
vendored
@@ -12,7 +12,7 @@ import (
|
|||||||
"rsc.io/letsencrypt"
|
"rsc.io/letsencrypt"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/Sirupsen/logrus/formatters/logstash"
|
logstash "github.com/bshuster-repo/logrus-logstash-hook"
|
||||||
"github.com/bugsnag/bugsnag-go"
|
"github.com/bugsnag/bugsnag-go"
|
||||||
"github.com/docker/distribution/configuration"
|
"github.com/docker/distribution/configuration"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
|
|||||||
16
vendor/github.com/docker/distribution/registry/storage/blob_test.go
generated
vendored
16
vendor/github.com/docker/distribution/registry/storage/blob_test.go
generated
vendored
@@ -13,18 +13,18 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/storage/cache/memory"
|
"github.com/docker/distribution/registry/storage/cache/memory"
|
||||||
"github.com/docker/distribution/registry/storage/driver/testdriver"
|
"github.com/docker/distribution/registry/storage/driver/testdriver"
|
||||||
"github.com/docker/distribution/testutil"
|
"github.com/docker/distribution/testutil"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestWriteSeek tests that the current file size can be
|
// TestWriteSeek tests that the current file size can be
|
||||||
// obtained using Seek
|
// obtained using Seek
|
||||||
func TestWriteSeek(t *testing.T) {
|
func TestWriteSeek(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
imageName, _ := reference.ParseNamed("foo/bar")
|
imageName, _ := reference.WithName("foo/bar")
|
||||||
driver := testdriver.New()
|
driver := testdriver.New()
|
||||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -60,7 +60,7 @@ func TestSimpleBlobUpload(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
imageName, _ := reference.ParseNamed("foo/bar")
|
imageName, _ := reference.WithName("foo/bar")
|
||||||
driver := testdriver.New()
|
driver := testdriver.New()
|
||||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -255,7 +255,7 @@ func TestSimpleBlobUpload(t *testing.T) {
|
|||||||
// other tests.
|
// other tests.
|
||||||
func TestSimpleBlobRead(t *testing.T) {
|
func TestSimpleBlobRead(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
imageName, _ := reference.ParseNamed("foo/bar")
|
imageName, _ := reference.WithName("foo/bar")
|
||||||
driver := testdriver.New()
|
driver := testdriver.New()
|
||||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -366,8 +366,8 @@ func TestBlobMount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
imageName, _ := reference.ParseNamed("foo/bar")
|
imageName, _ := reference.WithName("foo/bar")
|
||||||
sourceImageName, _ := reference.ParseNamed("foo/source")
|
sourceImageName, _ := reference.WithName("foo/source")
|
||||||
driver := testdriver.New()
|
driver := testdriver.New()
|
||||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -518,7 +518,7 @@ func TestBlobMount(t *testing.T) {
|
|||||||
// TestLayerUploadZeroLength uploads zero-length
|
// TestLayerUploadZeroLength uploads zero-length
|
||||||
func TestLayerUploadZeroLength(t *testing.T) {
|
func TestLayerUploadZeroLength(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
imageName, _ := reference.ParseNamed("foo/bar")
|
imageName, _ := reference.WithName("foo/bar")
|
||||||
driver := testdriver.New()
|
driver := testdriver.New()
|
||||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -530,7 +530,7 @@ func TestLayerUploadZeroLength(t *testing.T) {
|
|||||||
}
|
}
|
||||||
bs := repository.Blobs(ctx)
|
bs := repository.Blobs(ctx)
|
||||||
|
|
||||||
simpleUpload(t, bs, []byte{}, digest.DigestSha256EmptyTar)
|
simpleUpload(t, bs, []byte{}, digestSha256Empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
func simpleUpload(t *testing.T, bs distribution.BlobIngester, blob []byte, expectedDigest digest.Digest) {
|
func simpleUpload(t *testing.T, bs distribution.BlobIngester, blob []byte, expectedDigest digest.Digest) {
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/registry/storage/blobserver.go
generated
vendored
2
vendor/github.com/docker/distribution/registry/storage/blobserver.go
generated
vendored
@@ -7,8 +7,8 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/registry/storage/driver"
|
"github.com/docker/distribution/registry/storage/driver"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(stevvooe): This should configurable in the future.
|
// TODO(stevvooe): This should configurable in the future.
|
||||||
|
|||||||
4
vendor/github.com/docker/distribution/registry/storage/blobstore.go
generated
vendored
4
vendor/github.com/docker/distribution/registry/storage/blobstore.go
generated
vendored
@@ -5,8 +5,8 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/registry/storage/driver"
|
"github.com/docker/distribution/registry/storage/driver"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// blobStore implements the read side of the blob store interface over a
|
// blobStore implements the read side of the blob store interface over a
|
||||||
@@ -145,7 +145,7 @@ func (bs *blobStore) readlink(ctx context.Context, path string) (digest.Digest,
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
linked, err := digest.ParseDigest(string(content))
|
linked, err := digest.Parse(string(content))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|||||||
25
vendor/github.com/docker/distribution/registry/storage/blobwriter.go
generated
vendored
25
vendor/github.com/docker/distribution/registry/storage/blobwriter.go
generated
vendored
@@ -10,14 +10,19 @@ import (
|
|||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
storagedriver "github.com/docker/distribution/registry/storage/driver"
|
storagedriver "github.com/docker/distribution/registry/storage/driver"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errResumableDigestNotAvailable = errors.New("resumable digest not available")
|
errResumableDigestNotAvailable = errors.New("resumable digest not available")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// digestSha256Empty is the canonical sha256 digest of empty data
|
||||||
|
digestSha256Empty = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||||
|
)
|
||||||
|
|
||||||
// blobWriter is used to control the various aspects of resumable
|
// blobWriter is used to control the various aspects of resumable
|
||||||
// blob upload.
|
// blob upload.
|
||||||
type blobWriter struct {
|
type blobWriter struct {
|
||||||
@@ -234,12 +239,8 @@ func (bw *blobWriter) validateBlob(ctx context.Context, desc distribution.Descri
|
|||||||
// paths. We may be able to make the size-based check a stronger
|
// paths. We may be able to make the size-based check a stronger
|
||||||
// guarantee, so this may be defensive.
|
// guarantee, so this may be defensive.
|
||||||
if !verified {
|
if !verified {
|
||||||
digester := digest.Canonical.New()
|
digester := digest.Canonical.Digester()
|
||||||
|
verifier := desc.Digest.Verifier()
|
||||||
digestVerifier, err := digest.NewDigestVerifier(desc.Digest)
|
|
||||||
if err != nil {
|
|
||||||
return distribution.Descriptor{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the file from the backend driver and validate it.
|
// Read the file from the backend driver and validate it.
|
||||||
fr, err := newFileReader(ctx, bw.driver, bw.path, desc.Size)
|
fr, err := newFileReader(ctx, bw.driver, bw.path, desc.Size)
|
||||||
@@ -250,12 +251,12 @@ func (bw *blobWriter) validateBlob(ctx context.Context, desc distribution.Descri
|
|||||||
|
|
||||||
tr := io.TeeReader(fr, digester.Hash())
|
tr := io.TeeReader(fr, digester.Hash())
|
||||||
|
|
||||||
if _, err := io.Copy(digestVerifier, tr); err != nil {
|
if _, err := io.Copy(verifier, tr); err != nil {
|
||||||
return distribution.Descriptor{}, err
|
return distribution.Descriptor{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
canonical = digester.Digest()
|
canonical = digester.Digest()
|
||||||
verified = digestVerifier.Verified()
|
verified = verifier.Verified()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +314,7 @@ func (bw *blobWriter) moveBlob(ctx context.Context, desc distribution.Descriptor
|
|||||||
// If no data was received, we may not actually have a file on disk. Check
|
// If no data was received, we may not actually have a file on disk. Check
|
||||||
// the size here and write a zero-length file to blobPath if this is the
|
// the size here and write a zero-length file to blobPath if this is the
|
||||||
// case. For the most part, this should only ever happen with zero-length
|
// case. For the most part, this should only ever happen with zero-length
|
||||||
// tars.
|
// blobs.
|
||||||
if _, err := bw.blobStore.driver.Stat(ctx, bw.path); err != nil {
|
if _, err := bw.blobStore.driver.Stat(ctx, bw.path); err != nil {
|
||||||
switch err := err.(type) {
|
switch err := err.(type) {
|
||||||
case storagedriver.PathNotFoundError:
|
case storagedriver.PathNotFoundError:
|
||||||
@@ -321,8 +322,8 @@ func (bw *blobWriter) moveBlob(ctx context.Context, desc distribution.Descriptor
|
|||||||
// get a hash, then the underlying file is deleted, we risk moving
|
// get a hash, then the underlying file is deleted, we risk moving
|
||||||
// a zero-length blob into a nonzero-length blob location. To
|
// a zero-length blob into a nonzero-length blob location. To
|
||||||
// prevent this horrid thing, we employ the hack of only allowing
|
// prevent this horrid thing, we employ the hack of only allowing
|
||||||
// to this happen for the digest of an empty tar.
|
// to this happen for the digest of an empty blob.
|
||||||
if desc.Digest == digest.DigestSha256EmptyTar {
|
if desc.Digest == digestSha256Empty {
|
||||||
return bw.blobStore.driver.PutContent(ctx, blobPath, []byte{})
|
return bw.blobStore.driver.PutContent(ctx, blobPath, []byte{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
vendor/github.com/docker/distribution/registry/storage/cache/cachecheck/suite.go
generated
vendored
2
vendor/github.com/docker/distribution/registry/storage/cache/cachecheck/suite.go
generated
vendored
@@ -6,8 +6,8 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
|
||||||
"github.com/docker/distribution/registry/storage/cache"
|
"github.com/docker/distribution/registry/storage/cache"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CheckBlobDescriptorCache takes a cache implementation through a common set
|
// CheckBlobDescriptorCache takes a cache implementation through a common set
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package cache
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/docker/distribution/context"
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/opencontainers/go-digest"
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
)
|
)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user