mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Add Unit test to daemon.SearchRegistryForImages…
… and refactor a little bit some daemon on the way. - Move `SearchRegistryForImages` to a new file (`daemon/search.go`) as `daemon.go` is getting pretty big. - `registry.Service` is now an interface (allowing us to decouple it a little bit and thus unit test easily). - Add some unit test for `SearchRegistryForImages`. - Use UniqueExactMatch for search filters - And use empty restore id for now in client.ContainerStart. Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
parent
5812b6927c
commit
636c276f67
11 changed files with 493 additions and 110 deletions
|
@ -234,7 +234,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
|||
}
|
||||
|
||||
//start the container
|
||||
if err := cli.client.ContainerStart(ctx, createResponse.ID); err != nil {
|
||||
if err := cli.client.ContainerStart(ctx, createResponse.ID, ""); err != nil {
|
||||
// If we have holdHijackedConnection, we should notify
|
||||
// holdHijackedConnection we are going to exit and wait
|
||||
// to avoid the terminal are not restored.
|
||||
|
|
|
@ -113,7 +113,7 @@ func (cli *DockerCli) CmdStart(args ...string) error {
|
|||
})
|
||||
|
||||
// 3. Start the container.
|
||||
if err := cli.client.ContainerStart(ctx, container); err != nil {
|
||||
if err := cli.client.ContainerStart(ctx, container, ""); err != nil {
|
||||
cancelFun()
|
||||
<-cErr
|
||||
return err
|
||||
|
@ -147,7 +147,7 @@ func (cli *DockerCli) CmdStart(args ...string) error {
|
|||
func (cli *DockerCli) startContainersWithoutAttachments(ctx context.Context, containers []string) error {
|
||||
var failedContainers []string
|
||||
for _, container := range containers {
|
||||
if err := cli.client.ContainerStart(ctx, container); err != nil {
|
||||
if err := cli.client.ContainerStart(ctx, container, ""); err != nil {
|
||||
fmt.Fprintf(cli.err, "%s\n", err)
|
||||
failedContainers = append(failedContainers, container)
|
||||
} else {
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
@ -31,7 +30,6 @@ import (
|
|||
"github.com/docker/engine-api/types"
|
||||
containertypes "github.com/docker/engine-api/types/container"
|
||||
networktypes "github.com/docker/engine-api/types/network"
|
||||
registrytypes "github.com/docker/engine-api/types/registry"
|
||||
"github.com/docker/engine-api/types/strslice"
|
||||
// register graph drivers
|
||||
_ "github.com/docker/docker/daemon/graphdriver/register"
|
||||
|
@ -63,7 +61,6 @@ import (
|
|||
volumedrivers "github.com/docker/docker/volume/drivers"
|
||||
"github.com/docker/docker/volume/local"
|
||||
"github.com/docker/docker/volume/store"
|
||||
"github.com/docker/engine-api/types/filters"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/docker/libnetwork"
|
||||
nwconfig "github.com/docker/libnetwork/config"
|
||||
|
@ -93,7 +90,7 @@ type Daemon struct {
|
|||
configStore *Config
|
||||
statsCollector *statsCollector
|
||||
defaultLogConfig containertypes.LogConfig
|
||||
RegistryService *registry.Service
|
||||
RegistryService registry.Service
|
||||
EventsService *events.Events
|
||||
netController libnetwork.NetworkController
|
||||
volumes *store.VolumeStore
|
||||
|
@ -614,7 +611,7 @@ func (daemon *Daemon) registerLink(parent, child *container.Container, alias str
|
|||
|
||||
// NewDaemon sets up everything for the daemon to be able to service
|
||||
// requests from the webserver.
|
||||
func NewDaemon(config *Config, registryService *registry.Service, containerdRemote libcontainerd.Remote) (daemon *Daemon, err error) {
|
||||
func NewDaemon(config *Config, registryService registry.Service, containerdRemote libcontainerd.Remote) (daemon *Daemon, err error) {
|
||||
setDefaultMtu(config)
|
||||
|
||||
// Ensure we have compatible and valid configuration options
|
||||
|
@ -1144,88 +1141,7 @@ func configureVolumes(config *Config, rootUID, rootGID int) (*store.VolumeStore,
|
|||
|
||||
// AuthenticateToRegistry checks the validity of credentials in authConfig
|
||||
func (daemon *Daemon) AuthenticateToRegistry(ctx context.Context, authConfig *types.AuthConfig) (string, string, error) {
|
||||
return daemon.RegistryService.Auth(authConfig, dockerversion.DockerUserAgent(ctx))
|
||||
}
|
||||
|
||||
var acceptedSearchFilterTags = map[string]bool{
|
||||
"is-automated": true,
|
||||
"is-official": true,
|
||||
"stars": true,
|
||||
}
|
||||
|
||||
// SearchRegistryForImages queries the registry for images matching
|
||||
// term. authConfig is used to login.
|
||||
func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, filtersArgs string, term string,
|
||||
authConfig *types.AuthConfig,
|
||||
headers map[string][]string) (*registrytypes.SearchResults, error) {
|
||||
|
||||
searchFilters, err := filters.FromParam(filtersArgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := searchFilters.Validate(acceptedSearchFilterTags); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
unfilteredResult, err := daemon.RegistryService.Search(term, authConfig, dockerversion.DockerUserAgent(ctx), headers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var isAutomated, isOfficial bool
|
||||
var hasStarFilter = 0
|
||||
if searchFilters.Include("is-automated") {
|
||||
if searchFilters.ExactMatch("is-automated", "true") {
|
||||
isAutomated = true
|
||||
} else if !searchFilters.ExactMatch("is-automated", "false") {
|
||||
return nil, fmt.Errorf("Invalid filter 'is-automated=%s'", searchFilters.Get("is-automated"))
|
||||
}
|
||||
}
|
||||
if searchFilters.Include("is-official") {
|
||||
if searchFilters.ExactMatch("is-official", "true") {
|
||||
isOfficial = true
|
||||
} else if !searchFilters.ExactMatch("is-official", "false") {
|
||||
return nil, fmt.Errorf("Invalid filter 'is-official=%s'", searchFilters.Get("is-official"))
|
||||
}
|
||||
}
|
||||
if searchFilters.Include("stars") {
|
||||
hasStars := searchFilters.Get("stars")
|
||||
for _, hasStar := range hasStars {
|
||||
iHasStar, err := strconv.Atoi(hasStar)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invalid filter 'stars=%s'", hasStar)
|
||||
}
|
||||
if iHasStar > hasStarFilter {
|
||||
hasStarFilter = iHasStar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filteredResults := []registrytypes.SearchResult{}
|
||||
for _, result := range unfilteredResult.Results {
|
||||
if searchFilters.Include("is-automated") {
|
||||
if isAutomated != result.IsAutomated {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if searchFilters.Include("is-official") {
|
||||
if isOfficial != result.IsOfficial {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if searchFilters.Include("stars") {
|
||||
if result.StarCount < hasStarFilter {
|
||||
continue
|
||||
}
|
||||
}
|
||||
filteredResults = append(filteredResults, result)
|
||||
}
|
||||
|
||||
return ®istrytypes.SearchResults{
|
||||
Query: unfilteredResult.Query,
|
||||
NumResults: len(filteredResults),
|
||||
Results: filteredResults,
|
||||
}, nil
|
||||
return daemon.RegistryService.Auth(ctx, authConfig, dockerversion.DockerUserAgent(ctx))
|
||||
}
|
||||
|
||||
// IsShuttingDown tells whether the daemon is shutting down or not
|
||||
|
|
94
daemon/search.go
Normal file
94
daemon/search.go
Normal file
|
@ -0,0 +1,94 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/dockerversion"
|
||||
"github.com/docker/engine-api/types"
|
||||
"github.com/docker/engine-api/types/filters"
|
||||
registrytypes "github.com/docker/engine-api/types/registry"
|
||||
)
|
||||
|
||||
var acceptedSearchFilterTags = map[string]bool{
|
||||
"is-automated": true,
|
||||
"is-official": true,
|
||||
"stars": true,
|
||||
}
|
||||
|
||||
// SearchRegistryForImages queries the registry for images matching
|
||||
// term. authConfig is used to login.
|
||||
func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, filtersArgs string, term string,
|
||||
authConfig *types.AuthConfig,
|
||||
headers map[string][]string) (*registrytypes.SearchResults, error) {
|
||||
|
||||
searchFilters, err := filters.FromParam(filtersArgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := searchFilters.Validate(acceptedSearchFilterTags); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
unfilteredResult, err := daemon.RegistryService.Search(ctx, term, authConfig, dockerversion.DockerUserAgent(ctx), headers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var isAutomated, isOfficial bool
|
||||
var hasStarFilter = 0
|
||||
if searchFilters.Include("is-automated") {
|
||||
if searchFilters.UniqueExactMatch("is-automated", "true") {
|
||||
isAutomated = true
|
||||
} else if !searchFilters.UniqueExactMatch("is-automated", "false") {
|
||||
return nil, fmt.Errorf("Invalid filter 'is-automated=%s'", searchFilters.Get("is-automated"))
|
||||
}
|
||||
}
|
||||
if searchFilters.Include("is-official") {
|
||||
if searchFilters.UniqueExactMatch("is-official", "true") {
|
||||
isOfficial = true
|
||||
} else if !searchFilters.UniqueExactMatch("is-official", "false") {
|
||||
return nil, fmt.Errorf("Invalid filter 'is-official=%s'", searchFilters.Get("is-official"))
|
||||
}
|
||||
}
|
||||
if searchFilters.Include("stars") {
|
||||
hasStars := searchFilters.Get("stars")
|
||||
for _, hasStar := range hasStars {
|
||||
iHasStar, err := strconv.Atoi(hasStar)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invalid filter 'stars=%s'", hasStar)
|
||||
}
|
||||
if iHasStar > hasStarFilter {
|
||||
hasStarFilter = iHasStar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filteredResults := []registrytypes.SearchResult{}
|
||||
for _, result := range unfilteredResult.Results {
|
||||
if searchFilters.Include("is-automated") {
|
||||
if isAutomated != result.IsAutomated {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if searchFilters.Include("is-official") {
|
||||
if isOfficial != result.IsOfficial {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if searchFilters.Include("stars") {
|
||||
if result.StarCount < hasStarFilter {
|
||||
continue
|
||||
}
|
||||
}
|
||||
filteredResults = append(filteredResults, result)
|
||||
}
|
||||
|
||||
return ®istrytypes.SearchResults{
|
||||
Query: unfilteredResult.Query,
|
||||
NumResults: len(filteredResults),
|
||||
Results: filteredResults,
|
||||
}, nil
|
||||
}
|
357
daemon/search_test.go
Normal file
357
daemon/search_test.go
Normal file
|
@ -0,0 +1,357 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/engine-api/types"
|
||||
registrytypes "github.com/docker/engine-api/types/registry"
|
||||
)
|
||||
|
||||
type FakeService struct {
|
||||
registry.DefaultService
|
||||
|
||||
shouldReturnError bool
|
||||
|
||||
term string
|
||||
results []registrytypes.SearchResult
|
||||
}
|
||||
|
||||
func (s *FakeService) Search(ctx context.Context, term string, authConfig *types.AuthConfig, userAgent string, headers map[string][]string) (*registrytypes.SearchResults, error) {
|
||||
if s.shouldReturnError {
|
||||
return nil, fmt.Errorf("Search unknown error")
|
||||
}
|
||||
return ®istrytypes.SearchResults{
|
||||
Query: s.term,
|
||||
NumResults: len(s.results),
|
||||
Results: s.results,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func TestSearchRegistryForImagesErrors(t *testing.T) {
|
||||
errorCases := []struct {
|
||||
filtersArgs string
|
||||
shouldReturnError bool
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
expectedError: "Search unknown error",
|
||||
shouldReturnError: true,
|
||||
},
|
||||
{
|
||||
filtersArgs: "invalid json",
|
||||
expectedError: "invalid character 'i' looking for beginning of value",
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"type":{"custom":true}}`,
|
||||
expectedError: "Invalid filter 'type'",
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"is-automated":{"invalid":true}}`,
|
||||
expectedError: "Invalid filter 'is-automated=[invalid]'",
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"is-automated":{"true":true,"false":true}}`,
|
||||
expectedError: "Invalid filter 'is-automated",
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"is-official":{"invalid":true}}`,
|
||||
expectedError: "Invalid filter 'is-official=[invalid]'",
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"is-official":{"true":true,"false":true}}`,
|
||||
expectedError: "Invalid filter 'is-official",
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"stars":{"invalid":true}}`,
|
||||
expectedError: "Invalid filter 'stars=invalid'",
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"stars":{"1":true,"invalid":true}}`,
|
||||
expectedError: "Invalid filter 'stars=invalid'",
|
||||
},
|
||||
}
|
||||
for index, e := range errorCases {
|
||||
daemon := &Daemon{
|
||||
RegistryService: &FakeService{
|
||||
shouldReturnError: e.shouldReturnError,
|
||||
},
|
||||
}
|
||||
_, err := daemon.SearchRegistryForImages(context.Background(), e.filtersArgs, "term", nil, map[string][]string{})
|
||||
if err == nil {
|
||||
t.Errorf("%d: expected an error, got nothing", index)
|
||||
}
|
||||
if !strings.Contains(err.Error(), e.expectedError) {
|
||||
t.Errorf("%d: expected error to contain %s, got %s", index, e.expectedError, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchRegistryForImages(t *testing.T) {
|
||||
term := "term"
|
||||
successCases := []struct {
|
||||
filtersArgs string
|
||||
registryResults []registrytypes.SearchResult
|
||||
expectedResults []registrytypes.SearchResult
|
||||
}{
|
||||
{
|
||||
filtersArgs: "",
|
||||
registryResults: []registrytypes.SearchResult{},
|
||||
expectedResults: []registrytypes.SearchResult{},
|
||||
},
|
||||
{
|
||||
filtersArgs: "",
|
||||
registryResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
},
|
||||
},
|
||||
expectedResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"is-automated":{"true":true}}`,
|
||||
registryResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
},
|
||||
},
|
||||
expectedResults: []registrytypes.SearchResult{},
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"is-automated":{"true":true}}`,
|
||||
registryResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
IsAutomated: true,
|
||||
},
|
||||
},
|
||||
expectedResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
IsAutomated: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"is-automated":{"false":true}}`,
|
||||
registryResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
IsAutomated: true,
|
||||
},
|
||||
},
|
||||
expectedResults: []registrytypes.SearchResult{},
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"is-automated":{"false":true}}`,
|
||||
registryResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
IsAutomated: false,
|
||||
},
|
||||
},
|
||||
expectedResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
IsAutomated: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"is-official":{"true":true}}`,
|
||||
registryResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
},
|
||||
},
|
||||
expectedResults: []registrytypes.SearchResult{},
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"is-official":{"true":true}}`,
|
||||
registryResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
IsOfficial: true,
|
||||
},
|
||||
},
|
||||
expectedResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
IsOfficial: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"is-official":{"false":true}}`,
|
||||
registryResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
IsOfficial: true,
|
||||
},
|
||||
},
|
||||
expectedResults: []registrytypes.SearchResult{},
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"is-official":{"false":true}}`,
|
||||
registryResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
IsOfficial: false,
|
||||
},
|
||||
},
|
||||
expectedResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
IsOfficial: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"stars":{"0":true}}`,
|
||||
registryResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
StarCount: 0,
|
||||
},
|
||||
},
|
||||
expectedResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
StarCount: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"stars":{"1":true}}`,
|
||||
registryResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
StarCount: 0,
|
||||
},
|
||||
},
|
||||
expectedResults: []registrytypes.SearchResult{},
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"stars":{"1":true}}`,
|
||||
registryResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name0",
|
||||
Description: "description0",
|
||||
StarCount: 0,
|
||||
},
|
||||
{
|
||||
Name: "name1",
|
||||
Description: "description1",
|
||||
StarCount: 1,
|
||||
},
|
||||
},
|
||||
expectedResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name1",
|
||||
Description: "description1",
|
||||
StarCount: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
filtersArgs: `{"stars":{"1":true}, "is-official":{"true":true}, "is-automated":{"true":true}}`,
|
||||
registryResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name0",
|
||||
Description: "description0",
|
||||
StarCount: 0,
|
||||
IsOfficial: true,
|
||||
IsAutomated: true,
|
||||
},
|
||||
{
|
||||
Name: "name1",
|
||||
Description: "description1",
|
||||
StarCount: 1,
|
||||
IsOfficial: false,
|
||||
IsAutomated: true,
|
||||
},
|
||||
{
|
||||
Name: "name2",
|
||||
Description: "description2",
|
||||
StarCount: 1,
|
||||
IsOfficial: true,
|
||||
IsAutomated: false,
|
||||
},
|
||||
{
|
||||
Name: "name3",
|
||||
Description: "description3",
|
||||
StarCount: 2,
|
||||
IsOfficial: true,
|
||||
IsAutomated: true,
|
||||
},
|
||||
},
|
||||
expectedResults: []registrytypes.SearchResult{
|
||||
{
|
||||
Name: "name3",
|
||||
Description: "description3",
|
||||
StarCount: 2,
|
||||
IsOfficial: true,
|
||||
IsAutomated: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for index, s := range successCases {
|
||||
daemon := &Daemon{
|
||||
RegistryService: &FakeService{
|
||||
term: term,
|
||||
results: s.registryResults,
|
||||
},
|
||||
}
|
||||
results, err := daemon.SearchRegistryForImages(context.Background(), s.filtersArgs, term, nil, map[string][]string{})
|
||||
if err != nil {
|
||||
t.Errorf("%d: %v", index, err)
|
||||
}
|
||||
if results.Query != term {
|
||||
t.Errorf("%d: expected Query to be %s, got %s", index, term, results.Query)
|
||||
}
|
||||
if results.NumResults != len(s.expectedResults) {
|
||||
t.Errorf("%d: expected NumResults to be %d, got %d", index, len(s.expectedResults), results.NumResults)
|
||||
}
|
||||
for _, result := range results.Results {
|
||||
found := false
|
||||
for _, expectedResult := range s.expectedResults {
|
||||
if expectedResult.Name == result.Name &&
|
||||
expectedResult.Description == result.Description &&
|
||||
expectedResult.IsAutomated == result.IsAutomated &&
|
||||
expectedResult.IsOfficial == result.IsOfficial &&
|
||||
expectedResult.StarCount == result.StarCount {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("%d: expected results %v, got %v", index, s.expectedResults, results.Results)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ type ImagePullConfig struct {
|
|||
ProgressOutput progress.Output
|
||||
// RegistryService is the registry service to use for TLS configuration
|
||||
// and endpoint lookup.
|
||||
RegistryService *registry.Service
|
||||
RegistryService registry.Service
|
||||
// ImageEventLogger notifies events for a given image
|
||||
ImageEventLogger func(id, name, action string)
|
||||
// MetadataStore is the storage backend for distribution-specific
|
||||
|
|
|
@ -31,7 +31,7 @@ type ImagePushConfig struct {
|
|||
ProgressOutput progress.Output
|
||||
// RegistryService is the registry service to use for TLS configuration
|
||||
// and endpoint lookup.
|
||||
RegistryService *registry.Service
|
||||
RegistryService registry.Service
|
||||
// ImageEventLogger notifies events for a given image
|
||||
ImageEventLogger func(id, name, action string)
|
||||
// MetadataStore is the storage backend for distribution-specific
|
||||
|
|
|
@ -661,7 +661,7 @@ func TestMirrorEndpointLookup(t *testing.T) {
|
|||
}
|
||||
return false
|
||||
}
|
||||
s := Service{config: makeServiceConfig([]string{"my.mirror"}, nil)}
|
||||
s := DefaultService{config: makeServiceConfig([]string{"my.mirror"}, nil)}
|
||||
|
||||
imageName, err := reference.WithName(IndexName + "/test/image")
|
||||
if err != nil {
|
||||
|
|
|
@ -7,35 +7,50 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/engine-api/types"
|
||||
registrytypes "github.com/docker/engine-api/types/registry"
|
||||
)
|
||||
|
||||
// Service is a registry service. It tracks configuration data such as a list
|
||||
// Service is the interface defining what a registry service should implement.
|
||||
type Service interface {
|
||||
Auth(ctx context.Context, authConfig *types.AuthConfig, userAgent string) (status, token string, err error)
|
||||
LookupPullEndpoints(hostname string) (endpoints []APIEndpoint, err error)
|
||||
LookupPushEndpoints(hostname string) (endpoints []APIEndpoint, err error)
|
||||
ResolveRepository(name reference.Named) (*RepositoryInfo, error)
|
||||
ResolveIndex(name string) (*registrytypes.IndexInfo, error)
|
||||
Search(ctx context.Context, term string, authConfig *types.AuthConfig, userAgent string, headers map[string][]string) (*registrytypes.SearchResults, error)
|
||||
ServiceConfig() *registrytypes.ServiceConfig
|
||||
TLSConfig(hostname string) (*tls.Config, error)
|
||||
}
|
||||
|
||||
// DefaultService is a registry service. It tracks configuration data such as a list
|
||||
// of mirrors.
|
||||
type Service struct {
|
||||
type DefaultService struct {
|
||||
config *serviceConfig
|
||||
}
|
||||
|
||||
// NewService returns a new instance of Service ready to be
|
||||
// NewService returns a new instance of DefaultService ready to be
|
||||
// installed into an engine.
|
||||
func NewService(options ServiceOptions) *Service {
|
||||
return &Service{
|
||||
func NewService(options ServiceOptions) *DefaultService {
|
||||
return &DefaultService{
|
||||
config: newServiceConfig(options),
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceConfig returns the public registry service configuration.
|
||||
func (s *Service) ServiceConfig() *registrytypes.ServiceConfig {
|
||||
func (s *DefaultService) ServiceConfig() *registrytypes.ServiceConfig {
|
||||
return &s.config.ServiceConfig
|
||||
}
|
||||
|
||||
// Auth contacts the public registry with the provided credentials,
|
||||
// and returns OK if authentication was successful.
|
||||
// It can be used to verify the validity of a client's credentials.
|
||||
func (s *Service) Auth(authConfig *types.AuthConfig, userAgent string) (status, token string, err error) {
|
||||
func (s *DefaultService) Auth(ctx context.Context, authConfig *types.AuthConfig, userAgent string) (status, token string, err error) {
|
||||
// TODO Use ctx when searching for repositories
|
||||
serverAddress := authConfig.ServerAddress
|
||||
if serverAddress == "" {
|
||||
serverAddress = IndexServer
|
||||
|
@ -93,7 +108,8 @@ func splitReposSearchTerm(reposName string) (string, string) {
|
|||
|
||||
// Search queries the public registry for images matching the specified
|
||||
// search terms, and returns the results.
|
||||
func (s *Service) Search(term string, authConfig *types.AuthConfig, userAgent string, headers map[string][]string) (*registrytypes.SearchResults, error) {
|
||||
func (s *DefaultService) Search(ctx context.Context, term string, authConfig *types.AuthConfig, userAgent string, headers map[string][]string) (*registrytypes.SearchResults, error) {
|
||||
// TODO Use ctx when searching for repositories
|
||||
if err := validateNoScheme(term); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -130,12 +146,12 @@ func (s *Service) Search(term string, authConfig *types.AuthConfig, userAgent st
|
|||
|
||||
// ResolveRepository splits a repository name into its components
|
||||
// and configuration of the associated registry.
|
||||
func (s *Service) ResolveRepository(name reference.Named) (*RepositoryInfo, error) {
|
||||
func (s *DefaultService) ResolveRepository(name reference.Named) (*RepositoryInfo, error) {
|
||||
return newRepositoryInfo(s.config, name)
|
||||
}
|
||||
|
||||
// ResolveIndex takes indexName and returns index info
|
||||
func (s *Service) ResolveIndex(name string) (*registrytypes.IndexInfo, error) {
|
||||
func (s *DefaultService) ResolveIndex(name string) (*registrytypes.IndexInfo, error) {
|
||||
return newIndexInfo(s.config, name)
|
||||
}
|
||||
|
||||
|
@ -155,25 +171,25 @@ func (e APIEndpoint) ToV1Endpoint(userAgent string, metaHeaders http.Header) (*V
|
|||
}
|
||||
|
||||
// TLSConfig constructs a client TLS configuration based on server defaults
|
||||
func (s *Service) TLSConfig(hostname string) (*tls.Config, error) {
|
||||
func (s *DefaultService) TLSConfig(hostname string) (*tls.Config, error) {
|
||||
return newTLSConfig(hostname, isSecureIndex(s.config, hostname))
|
||||
}
|
||||
|
||||
func (s *Service) tlsConfigForMirror(mirrorURL *url.URL) (*tls.Config, error) {
|
||||
func (s *DefaultService) tlsConfigForMirror(mirrorURL *url.URL) (*tls.Config, error) {
|
||||
return s.TLSConfig(mirrorURL.Host)
|
||||
}
|
||||
|
||||
// LookupPullEndpoints creates a list of endpoints to try to pull from, in order of preference.
|
||||
// It gives preference to v2 endpoints over v1, mirrors over the actual
|
||||
// registry, and HTTPS over plain HTTP.
|
||||
func (s *Service) LookupPullEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
||||
func (s *DefaultService) LookupPullEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
||||
return s.lookupEndpoints(hostname)
|
||||
}
|
||||
|
||||
// LookupPushEndpoints creates a list of endpoints to try to push to, in order of preference.
|
||||
// It gives preference to v2 endpoints over v1, and HTTPS over plain HTTP.
|
||||
// Mirrors are not included.
|
||||
func (s *Service) LookupPushEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
||||
func (s *DefaultService) LookupPushEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
||||
allEndpoints, err := s.lookupEndpoints(hostname)
|
||||
if err == nil {
|
||||
for _, endpoint := range allEndpoints {
|
||||
|
@ -185,7 +201,7 @@ func (s *Service) LookupPushEndpoints(hostname string) (endpoints []APIEndpoint,
|
|||
return endpoints, err
|
||||
}
|
||||
|
||||
func (s *Service) lookupEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
||||
func (s *DefaultService) lookupEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
||||
endpoints, err = s.lookupV2Endpoints(hostname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/docker/go-connections/tlsconfig"
|
||||
)
|
||||
|
||||
func (s *Service) lookupV1Endpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
||||
func (s *DefaultService) lookupV1Endpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
||||
var cfg = tlsconfig.ServerDefault
|
||||
tlsConfig := &cfg
|
||||
if hostname == DefaultNamespace {
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/docker/go-connections/tlsconfig"
|
||||
)
|
||||
|
||||
func (s *Service) lookupV2Endpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
||||
func (s *DefaultService) lookupV2Endpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
||||
var cfg = tlsconfig.ServerDefault
|
||||
tlsConfig := &cfg
|
||||
if hostname == DefaultNamespace || hostname == DefaultV1Registry.Host {
|
||||
|
|
Loading…
Reference in a new issue