Skip to content

Commit

Permalink
Merge pull request #5 from miminar/1.4.1-beta2
Browse files Browse the repository at this point in the history
Add --add-registry and --block-registry options to docker daemon
  • Loading branch information
rhatdan committed Jan 30, 2015
2 parents 0af307b + 7950901 commit b024f0f
Show file tree
Hide file tree
Showing 14 changed files with 97 additions and 28 deletions.
1 change: 1 addition & 0 deletions api/server/server.go
Expand Up @@ -565,6 +565,7 @@ func postImagesCreate(eng *engine.Engine, version version.Version, w http.Respon
job.SetenvBool("parallel", version.GreaterThan("1.3"))
job.SetenvJson("metaHeaders", metaHeaders)
job.SetenvJson("authConfig", authConfig)
job.SetenvBool("protectOfficialRegistry", false)
} else { //import
if tag == "" {
repo, tag = parsers.ParseRepositoryTag(repo)
Expand Down
1 change: 1 addition & 0 deletions builder/internals.go
Expand Up @@ -438,6 +438,7 @@ func (b *Builder) pullImage(name string) (*imagepkg.Image, error) {
job.SetenvBool("json", b.StreamFormatter.Json())
job.SetenvBool("parallel", true)
job.SetenvJson("authConfig", pullRegistryAuth)
job.SetenvBool("protectOfficialRegistry", true)
job.Stdout.Add(b.OutOld)
if err := job.Run(); err != nil {
return nil, err
Expand Down
2 changes: 2 additions & 0 deletions contrib/completion/bash/docker
Expand Up @@ -895,7 +895,9 @@ _docker() {
)

local main_options_with_args="
--add-registry
--bip
--block-registry
--bridge -b
--dns
--dns-search
Expand Down
4 changes: 2 additions & 2 deletions contrib/completion/fish/docker.fish
Expand Up @@ -43,9 +43,11 @@ function __fish_print_docker_repositories --description 'Print a list of docker
end

# common options
complete -c docker -f -n '__fish_docker_no_subcommand' -l add-registry -d "[EXPERIMENTAL] Each given registry will be queried before a public Docker registry during image pulls or searches. They will be searched in the order given and treated as insecure."
complete -c docker -f -n '__fish_docker_no_subcommand' -l api-enable-cors -d 'Enable CORS headers in the remote API'
complete -c docker -f -n '__fish_docker_no_subcommand' -s b -l bridge -d 'Attach containers to a pre-existing network bridge'
complete -c docker -f -n '__fish_docker_no_subcommand' -l bip -d "Use this CIDR notation address for the network bridge's IP, not compatible with -b"
complete -c docker -f -n '__fish_docker_no_subcommand' -l block-registry -d '[EXPERIMENTAL] Prevent docker daemon from contacting specified registries. Special keyword "public" represents public Docker registry.'
complete -c docker -f -n '__fish_docker_no_subcommand' -s D -l debug -d 'Enable debug mode'
complete -c docker -f -n '__fish_docker_no_subcommand' -s d -l daemon -d 'Enable daemon mode'
complete -c docker -f -n '__fish_docker_no_subcommand' -l dns -d 'Force Docker to use specific DNS servers'
Expand All @@ -64,8 +66,6 @@ complete -c docker -f -n '__fish_docker_no_subcommand' -l iptables -d "Enable Do
complete -c docker -f -n '__fish_docker_no_subcommand' -l mtu -d 'Set the containers network MTU'
complete -c docker -f -n '__fish_docker_no_subcommand' -s p -l pidfile -d 'Path to use for daemon PID file'
complete -c docker -f -n '__fish_docker_no_subcommand' -l registry-mirror -d "Specify a preferred Docker registry mirror for pulls from official registry"
complete -c docker -f -n '__fish_docker_no_subcommand' -l registry-replace -d "Registry that shall replace official registry and index. Registry is expected to be insecure."
complete -c docker -f -n '__fish_docker_no_subcommand' -l registry-prepend -d "Each given registry will be prepended to a list of registries queried during image pulls or searches. The last registry given will be queried first. They will be treated as insecure."
complete -c docker -f -n '__fish_docker_no_subcommand' -s s -l storage-driver -d 'Force the Docker runtime to use a specific storage driver'
complete -c docker -f -n '__fish_docker_no_subcommand' -l selinux-enabled -d 'Enable selinux support. SELinux does not presently support the BTRFS storage driver'
complete -c docker -f -n '__fish_docker_no_subcommand' -l storage-opt -d 'Set storage driver options'
Expand Down
7 changes: 7 additions & 0 deletions daemon/config.go
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/docker/docker/daemon/networkdriver"
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/registry"
)

const (
Expand Down Expand Up @@ -42,6 +43,8 @@ type Config struct {
Context map[string][]string
TrustKeyPath string
Labels []string
BlockedRegistries opts.ListOpts
AdditionalRegistries opts.ListOpts
}

// InstallFlags adds command-line options to the top-level flag parser for
Expand Down Expand Up @@ -71,6 +74,10 @@ func (config *Config) InstallFlags() {
opts.IPListVar(&config.Dns, []string{"#dns", "-dns"}, "Force Docker to use specific DNS servers")
opts.DnsSearchListVar(&config.DnsSearch, []string{"-dns-search"}, "Force Docker to use specific DNS search domains")
opts.LabelListVar(&config.Labels, []string{"-label"}, "Set key=value labels to the daemon (displayed in `docker info`)")
config.BlockedRegistries = opts.NewListOpts(registry.ValidateIndexName)
flag.Var(&config.BlockedRegistries, []string{"-block-registry"}, "[EXPERIMENTAL] Prevent Docker daemon from contacting specified registries. Special keyword \"public\" represents public Docker registry.")
config.AdditionalRegistries = opts.NewListOpts(registry.ValidateIndexName)
flag.Var(&config.AdditionalRegistries, []string{"-add-registry"}, "[EXPERIMENTAL] Each given registry will be queried before a public Docker registry during image pulls or searches. They will be searched in the order given and treated as insecure.")
}

func getDefaultNetworkMtu() int {
Expand Down
20 changes: 12 additions & 8 deletions docker/daemon.go
Expand Up @@ -80,19 +80,23 @@ func mainDaemon() {
return
}

if *registryCfg.DefaultRegistry != "" {
defaultRegistry, err := registry.ValidateIndexName(*registryCfg.DefaultRegistry)
if err != nil {
log.Fatal("Given invalid default registry \"%s\": %s", *registryCfg.DefaultRegistry, err.Error())
for _, r := range daemonCfg.BlockedRegistries.GetAll() {
if r == "public" {
r = registry.INDEXNAME
}
registry.BlockedRegistries[r] = struct{}{}
if r == registry.INDEXNAME {
registry.RegistryList = []string{}
}
registry.RegistryList[0] = defaultRegistry
}

for _, r := range registryCfg.AdditionalRegistries.GetAll() {
if r != "" {
registry.RegistryList = append([]string{r}, registry.RegistryList...)
newRegistryList := []string{}
for _, r := range daemonCfg.AdditionalRegistries.GetAll() {
if _, ok := registry.BlockedRegistries[r]; !ok {
newRegistryList = append(newRegistryList, r)
}
}
registry.RegistryList = append(newRegistryList, registry.RegistryList...)

eng := engine.New()
signal.Trap(eng.Shutdown)
Expand Down
6 changes: 6 additions & 0 deletions docker/docker.go
Expand Up @@ -84,6 +84,12 @@ func main() {
log.Fatal(err)
}

for _, lopt := range []string{"-add-registry", "-block-registry"} {
if flag.IsSet(lopt) {
log.Fatalf("The -%s option is recognized only by Docker daemon.", lopt)
}
}

var (
cli *client.DockerCli
tlsConfig tls.Config
Expand Down
12 changes: 6 additions & 6 deletions docs/man/docker.1.md
Expand Up @@ -34,6 +34,9 @@ unix://[/path/to/socket] to use.
The socket(s) to bind to in daemon mode specified using one or more
tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.

**--add-registry**=[]
**EXPERIMENTAL** Each given registry will be queried before a public Docker registry during image pulls or searches. They will be searched in the order given and treated as insecure. Registry mirrors won't apply to them.

**--api-enable-cors**=*true*|*false*
Enable CORS headers in the remote API. Default is false.

Expand All @@ -43,6 +46,9 @@ unix://[/path/to/socket] to use.
**--bip**=""
Use the provided CIDR notation address for the dynamically created bridge (docker0); Mutually exclusive of \-b

**--block-registry**=[]
**EXPERIMENTAL** Prevent Docker daemon from contacting specified registries. Special keyword "public" represents public Docker registry.

**-d**=*true*|*false*
Enable daemon mode. Default is false.

Expand Down Expand Up @@ -91,12 +97,6 @@ unix://[/path/to/socket] to use.
**--registry-mirror**=<scheme>://<host>
Prepend a registry mirror to be used for image pulls from public Docker registry. May be specified multiple times.

**--registry-prepend**=[]
Each given registry will be prepended to a list of registries queried during image pulls or searches. The last registry given will be queried first. They will be treated as insecure. Registry mirrors won't apply to them.

**--registry-replace**=""
Registry that shall replace official Docker registry and index (e.g. 10.172.10.2:5000, private-registry.foo.bar). Additional registries added with --registry-prepend will be queried before this one. Use this option if you do not want to query official registry at all. It will be treated as insecure. Registry mirrors won't apply to given registry.

**-s**=""
Force the Docker runtime to use a specific storage driver.

Expand Down
4 changes: 3 additions & 1 deletion graph/export.go
Expand Up @@ -40,7 +40,9 @@ func (s *TagStore) CmdImageExport(job *engine.Job) engine.Status {
}
}
for _, name := range job.Args {
name = registry.NormalizeLocalName(name)
if _, exists := s.Repositories[name]; !exists {
name = registry.NormalizeLocalName(name)
}
log.Debugf("Serializing %s", name)
rootRepo := s.Repositories[name]
if rootRepo != nil {
Expand Down
7 changes: 7 additions & 0 deletions graph/pull.go
Expand Up @@ -28,6 +28,13 @@ func (s *TagStore) CmdRegistryPull(job *engine.Job) engine.Status {
// the matching image is found.
if registry.RepositoryNameHasIndex(tmp) {
registries = []string{""}
} else if len(registries) == 0 {
return job.Errorf("No configured registry to pull from.")
} else if job.GetenvBool("protectOfficialRegistry") && registries[0] != registry.INDEXNAME {
// We must ensure that registry missing hostname will be pulled from
// official one, if the `protectOfficialRegistry` tells us so.
registries = []string{""}
tmp = fmt.Sprintf("%s/%s", registry.INDEXNAME, tmp)
}
for i, r := range registries {
if i > 0 {
Expand Down
8 changes: 6 additions & 2 deletions graph/tags.go
Expand Up @@ -178,7 +178,9 @@ func (store *TagStore) Delete(repoName, tag string) (bool, error) {
if err := store.reload(); err != nil {
return false, err
}
repoName = registry.NormalizeLocalName(repoName)
if _, exists := store.Repositories[repoName]; !exists {
repoName = registry.NormalizeLocalName(repoName)
}
if r, exists := store.Repositories[repoName]; exists {
if tag != "" {
if _, exists2 := r[tag]; exists2 {
Expand Down Expand Up @@ -240,10 +242,12 @@ func (store *TagStore) Get(repoName string) (Repository, error) {
if err := store.reload(); err != nil {
return nil, err
}
repoName = registry.NormalizeLocalName(repoName)
if r, exists := store.Repositories[repoName]; exists {
return r, nil
}
if r, exists := store.Repositories[registry.NormalizeLocalName(repoName)]; exists {
return r, nil
}
return nil, nil
}

Expand Down
35 changes: 26 additions & 9 deletions registry/config.go
Expand Up @@ -16,10 +16,8 @@ import (

// Options holds command line options.
type Options struct {
Mirrors opts.ListOpts
InsecureRegistries opts.ListOpts
DefaultRegistry *string
AdditionalRegistries opts.ListOpts
Mirrors opts.ListOpts
InsecureRegistries opts.ListOpts
}

const (
Expand All @@ -33,6 +31,8 @@ const (
)

var (
// A set of blocked registries
BlockedRegistries map[string]struct{}
// List of registries to query.
RegistryList = []string{INDEXNAME}
ErrInvalidRepositoryName = errors.New("Invalid repository name (ex: \"registry.domain.tld/myrepos\")")
Expand All @@ -41,8 +41,15 @@ var (
validRepo = regexp.MustCompile(`^([a-z0-9-_.]+)$`)
)

func init() {
BlockedRegistries = make(map[string]struct{})
}

// IndexServerName returns the name of default index server.
func IndexServerName() string {
if len(RegistryList) < 1 {
return ""
}
return RegistryList[0]
}

Expand All @@ -53,6 +60,8 @@ func IndexServerAddress(indexName string) string {
return INDEXSERVER
} else if indexName != "" {
return fmt.Sprintf("http://%s/v1/", indexName)
} else if IndexServerName() == "" {
return ""
} else {
return fmt.Sprintf("http://%s/v1/", IndexServerName())
}
Expand All @@ -65,6 +74,8 @@ func RegistryServerAddress(indexName string) string {
return REGISTRYSERVER
} else if indexName != "" {
return fmt.Sprintf("http://%s/v2/", indexName)
} else if IndexServerName() == "" {
return ""
} else {
return fmt.Sprintf("http://%s/v2/", IndexServerName())
}
Expand All @@ -77,9 +88,6 @@ func (options *Options) InstallFlags() {
flag.Var(&options.Mirrors, []string{"-registry-mirror"}, "Specify a preferred Docker registry mirror for pulls from official registry")
options.InsecureRegistries = opts.NewListOpts(ValidateIndexName)
flag.Var(&options.InsecureRegistries, []string{"-insecure-registry"}, "Enable insecure communication with specified registries (no certificate verification for HTTPS and enable HTTP fallback) (e.g., localhost:5000 or 10.20.0.0/16)")
options.DefaultRegistry = flag.String([]string{"-registry-replace"}, "", "Registry that shall replace official registry and index. It will be treated as insecure.")
options.AdditionalRegistries = opts.NewListOpts(ValidateIndexName)
flag.Var(&options.AdditionalRegistries, []string{"-registry-prepend"}, "Each given registry will be prepended to a list of registries queried during image pulls or searches. The last registry given will be queried first. They will be treated as insecure.")
}

type netIPNet net.IPNet
Expand Down Expand Up @@ -234,8 +242,13 @@ func ValidateMirror(val string) (string, error) {
// ValidateIndexName validates an index name.
func ValidateIndexName(val string) (string, error) {
// 'index.docker.io' => 'docker.io'
if val == "index."+IndexServerName() {
val = IndexServerName()
if val == "index."+INDEXNAME {
val = INDEXNAME
}
for _, r := range RegistryList {
if val == "index."+r {
val = r
}
}
// *TODO: Check if valid hostname[:port]/ip[:port]?
return val, nil
Expand Down Expand Up @@ -373,6 +386,10 @@ func (config *ServiceConfig) NewRepositoryInfo(reposName string) (*RepositoryInf
RemoteName: remoteName,
}

if _, ok := BlockedRegistries[indexName]; ok {
return nil, fmt.Errorf("Blocked registry \"%s\"", indexName)
}

var err error
repoInfo.Index, err = config.NewIndexInfo(indexName)
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions registry/service.go
Expand Up @@ -55,6 +55,9 @@ func (s *Service) Auth(job *engine.Job) engine.Status {
// Use the official registry address if not specified.
addr = IndexServerAddress("")
}
if addr == "" {
return job.Errorf("No configured registry to authenticate to.")
}

if index, err = ResolveIndexInfo(job, addr); err != nil {
return job.Error(err)
Expand Down Expand Up @@ -136,6 +139,8 @@ func (s *Service) Search(job *engine.Job) engine.Status {
if err := doSearch(term); err != nil {
return job.Error(err)
}
} else if len(RegistryList) < 1 {
return job.Errorf("No configured repository to search.")
} else {
var (
err error
Expand Down
13 changes: 13 additions & 0 deletions registry/session.go
Expand Up @@ -200,13 +200,26 @@ func (r *Session) GetRemoteImageLayer(imgID, registry string, token []string, im
return res.Body, nil
}

func isEndpointBlocked(endpoint string) bool {
if parsedURL, err := url.Parse(endpoint); err == nil {
if _, ok := BlockedRegistries[parsedURL.Host]; !ok {
return false
}
}
return true
}

func (r *Session) GetRemoteTags(registries []string, repository string, token []string) (map[string]string, error) {
if strings.Count(repository, "/") == 0 {
// This will be removed once the Registry supports auto-resolution on
// the "library" namespace
repository = "library/" + repository
}
for _, host := range registries {
if isEndpointBlocked(host) {
log.Errorf("Cannot query blocked registry at %s for remote tags.", host)
continue
}
endpoint := fmt.Sprintf("%srepositories/%s/tags", host, repository)
req, err := r.reqFactory.NewRequest("GET", endpoint, nil)

Expand Down

0 comments on commit b024f0f

Please sign in to comment.