Skip to content

Commit

Permalink
Merge pull request moby#33151 from nwt/push-foreign-layers
Browse files Browse the repository at this point in the history
Add daemon option to push foreign layers
  • Loading branch information
thaJeztah authored May 17, 2017
2 parents 7658851 + 67fdf57 commit a30ef99
Show file tree
Hide file tree
Showing 16 changed files with 430 additions and 36 deletions.
8 changes: 5 additions & 3 deletions api/types/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import (

// ServiceConfig stores daemon registry services configuration.
type ServiceConfig struct {
InsecureRegistryCIDRs []*NetIPNet `json:"InsecureRegistryCIDRs"`
IndexConfigs map[string]*IndexInfo `json:"IndexConfigs"`
Mirrors []string
AllowNondistributableArtifactsCIDRs []*NetIPNet
AllowNondistributableArtifactsHostnames []string
InsecureRegistryCIDRs []*NetIPNet `json:"InsecureRegistryCIDRs"`
IndexConfigs map[string]*IndexInfo `json:"IndexConfigs"`
Mirrors []string
}

// NetIPNet is the net.IPNet type, which can be marshalled and
Expand Down
2 changes: 2 additions & 0 deletions cmd/dockerd/daemon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ func TestLoadDaemonConfigWithEmbeddedOptions(t *testing.T) {

func TestLoadDaemonConfigWithRegistryOptions(t *testing.T) {
content := `{
"allow-nondistributable-artifacts": ["allow-nondistributable-artifacts.com"],
"registry-mirrors": ["https://mirrors.docker.com"],
"insecure-registries": ["https://insecure.docker.com"]
}`
Expand All @@ -142,6 +143,7 @@ func TestLoadDaemonConfigWithRegistryOptions(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, loadedConfig)

assert.Len(t, loadedConfig.AllowNondistributableArtifacts, 1)
assert.Len(t, loadedConfig.Mirrors, 1)
assert.Len(t, loadedConfig.InsecureRegistries, 1)
}
1 change: 1 addition & 0 deletions contrib/completion/bash/docker
Original file line number Diff line number Diff line change
Expand Up @@ -1969,6 +1969,7 @@ _docker_daemon() {
local options_with_args="
$global_options_with_args
--add-runtime
--allow-nondistributable-artifacts
--api-cors-header
--authorization-plugin
--bip
Expand Down
1 change: 1 addition & 0 deletions contrib/completion/zsh/_docker
Original file line number Diff line number Diff line change
Expand Up @@ -2603,6 +2603,7 @@ __docker_subcommand() {
_arguments $(__docker_arguments) \
$opts_help \
"($help)*--add-runtime=[Register an additional OCI compatible runtime]:runtime:__docker_complete_runtimes" \
"($help)*--allow-nondistributable-artifacts=[Push nondistributable artifacts to specified registries]:registry: " \
"($help)--api-cors-header=[CORS headers in the Engine API]:CORS headers: " \
"($help)*--authorization-plugin=[Authorization plugins to load]" \
"($help -b --bridge)"{-b=,--bridge=}"[Attach containers to a network bridge]:bridge:_net_interfaces" \
Expand Down
28 changes: 28 additions & 0 deletions daemon/reload.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ func (daemon *Daemon) Reload(conf *config.Config) (err error) {
if err := daemon.reloadLabels(conf, attributes); err != nil {
return err
}
if err := daemon.reloadAllowNondistributableArtifacts(conf, attributes); err != nil {
return err
}
if err := daemon.reloadInsecureRegistries(conf, attributes); err != nil {
return err
}
Expand Down Expand Up @@ -217,6 +220,31 @@ func (daemon *Daemon) reloadLabels(conf *config.Config, attributes map[string]st
return nil
}

// reloadAllowNondistributableArtifacts updates the configuration with allow-nondistributable-artifacts options
// and updates the passed attributes.
func (daemon *Daemon) reloadAllowNondistributableArtifacts(conf *config.Config, attributes map[string]string) error {
// Update corresponding configuration.
if conf.IsValueSet("allow-nondistributable-artifacts") {
daemon.configStore.AllowNondistributableArtifacts = conf.AllowNondistributableArtifacts
if err := daemon.RegistryService.LoadAllowNondistributableArtifacts(conf.AllowNondistributableArtifacts); err != nil {
return err
}
}

// Prepare reload event attributes with updatable configurations.
if daemon.configStore.AllowNondistributableArtifacts != nil {
v, err := json.Marshal(daemon.configStore.AllowNondistributableArtifacts)
if err != nil {
return err
}
attributes["allow-nondistributable-artifacts"] = string(v)
} else {
attributes["allow-nondistributable-artifacts"] = "[]"
}

return nil
}

// reloadInsecureRegistries updates configuration with insecure registry option
// and updates the passed attributes
func (daemon *Daemon) reloadInsecureRegistries(conf *config.Config, attributes map[string]string) error {
Expand Down
56 changes: 56 additions & 0 deletions daemon/reload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package daemon

import (
"reflect"
"sort"
"testing"
"time"

Expand Down Expand Up @@ -40,6 +41,61 @@ func TestDaemonReloadLabels(t *testing.T) {
}
}

func TestDaemonReloadAllowNondistributableArtifacts(t *testing.T) {
daemon := &Daemon{
configStore: &config.Config{},
}

// Initialize daemon with some registries.
daemon.RegistryService = registry.NewService(registry.ServiceOptions{
AllowNondistributableArtifacts: []string{
"127.0.0.0/8",
"10.10.1.11:5000",
"10.10.1.22:5000", // This will be removed during reload.
"docker1.com",
"docker2.com", // This will be removed during reload.
},
})

registries := []string{
"127.0.0.0/8",
"10.10.1.11:5000",
"10.10.1.33:5000", // This will be added during reload.
"docker1.com",
"docker3.com", // This will be added during reload.
}

newConfig := &config.Config{
CommonConfig: config.CommonConfig{
ServiceOptions: registry.ServiceOptions{
AllowNondistributableArtifacts: registries,
},
ValuesSet: map[string]interface{}{
"allow-nondistributable-artifacts": registries,
},
},
}

if err := daemon.Reload(newConfig); err != nil {
t.Fatal(err)
}

actual := []string{}
serviceConfig := daemon.RegistryService.ServiceConfig()
for _, value := range serviceConfig.AllowNondistributableArtifactsCIDRs {
actual = append(actual, value.String())
}
for _, value := range serviceConfig.AllowNondistributableArtifactsHostnames {
actual = append(actual, value)
}

sort.Strings(registries)
sort.Strings(actual)
if !reflect.DeepEqual(registries, actual) {
t.Fatalf("expected %v, got %v\n", registries, actual)
}
}

func TestDaemonReloadMirrors(t *testing.T) {
daemon := &Daemon{}
daemon.RegistryService = registry.NewService(registry.ServiceOptions{
Expand Down
20 changes: 14 additions & 6 deletions distribution/pull_v2_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,28 @@ func (ld *v2LayerDescriptor) Descriptor() distribution.Descriptor {
}

func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekCloser, error) {
blobs := ld.repo.Blobs(ctx)
rsc, err := blobs.Open(ctx, ld.digest)

if len(ld.src.URLs) == 0 {
blobs := ld.repo.Blobs(ctx)
return blobs.Open(ctx, ld.digest)
return rsc, err
}

var (
err error
rsc distribution.ReadSeekCloser
)
// We're done if the registry has this blob.
if err == nil {
// Seek does an HTTP GET. If it succeeds, the blob really is accessible.
if _, err = rsc.Seek(0, os.SEEK_SET); err == nil {
return rsc, nil
}
rsc.Close()
}

// Find the first URL that results in a 200 result code.
for _, url := range ld.src.URLs {
logrus.Debugf("Pulling %v from foreign URL %v", ld.digest, url)
rsc = transport.NewHTTPReadSeeker(http.DefaultClient, url, nil)

// Seek does an HTTP GET. If it succeeds, the blob really is accessible.
_, err = rsc.Seek(0, os.SEEK_SET)
if err == nil {
break
Expand Down
13 changes: 9 additions & 4 deletions distribution/push_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, ref reference.NamedTagged, id
hmacKey: hmacKey,
repoInfo: p.repoInfo.Name,
ref: p.ref,
endpoint: p.endpoint,
repo: p.repo,
pushState: &p.pushState,
}
Expand Down Expand Up @@ -239,6 +240,7 @@ type v2PushDescriptor struct {
hmacKey []byte
repoInfo reference.Named
ref reference.Named
endpoint registry.APIEndpoint
repo distribution.Repository
pushState *pushState
remoteDescriptor distribution.Descriptor
Expand All @@ -259,10 +261,13 @@ func (pd *v2PushDescriptor) DiffID() layer.DiffID {
}

func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.Output) (distribution.Descriptor, error) {
if fs, ok := pd.layer.(distribution.Describable); ok {
if d := fs.Descriptor(); len(d.URLs) > 0 {
progress.Update(progressOutput, pd.ID(), "Skipped foreign layer")
return d, nil
// Skip foreign layers unless this registry allows nondistributable artifacts.
if !pd.endpoint.AllowNondistributableArtifacts {
if fs, ok := pd.layer.(distribution.Describable); ok {
if d := fs.Descriptor(); len(d.URLs) > 0 {
progress.Update(progressOutput, pd.ID(), "Skipped foreign layer")
return d, nil
}
}
}

Expand Down
30 changes: 30 additions & 0 deletions docs/reference/commandline/dockerd.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ A self-sufficient runtime for containers.

Options:
--add-runtime runtime Register an additional OCI compatible runtime (default [])
--allow-nondistributable-artifacts list Push nondistributable artifacts to specified registries (default [])
--api-cors-header string Set CORS headers in the Engine API
--authorization-plugin list Authorization plugins to load (default [])
--bip string Specify network bridge IP
Expand Down Expand Up @@ -828,6 +829,32 @@ To set the DNS search domain for all Docker containers, use:
$ sudo dockerd --dns-search example.com
```

#### Allow push of nondistributable artifacts

Some images (e.g., Windows base images) contain artifacts whose distribution is
restricted by license. When these images are pushed to a registry, restricted
artifacts are not included.

To override this behavior for specific registries, use the
`--allow-nondistributable-artifacts` option in one of the following forms:

* `--allow-nondistributable-artifacts myregistry:5000` tells the Docker daemon
to push nondistributable artifacts to myregistry:5000.
* `--allow-nondistributable-artifacts 10.1.0.0/16` tells the Docker daemon to
push nondistributable artifacts to all registries whose resolved IP address
is within the subnet described by the CIDR syntax.

This option can be used multiple times.

This option is useful when pushing images containing nondistributable artifacts
to a registry on an air-gapped network so hosts on that network can pull the
images without connecting to another server.

> **Warning**: Nondistributable artifacts typically have restrictions on how
> and where they can be distributed and shared. Only use this feature to push
> artifacts to private registries and ensure that you are in compliance with
> any terms that cover redistributing nondistributable artifacts.
#### Insecure registries

Docker considers a private registry either secure or insecure. In the rest of
Expand Down Expand Up @@ -1261,6 +1288,7 @@ This is a full example of the allowed configuration options on Linux:
"default-gateway-v6": "",
"icc": false,
"raw-logs": false,
"allow-nondistributable-artifacts": [],
"registry-mirrors": [],
"seccomp-profile": "",
"insecure-registries": [],
Expand Down Expand Up @@ -1330,6 +1358,7 @@ This is a full example of the allowed configuration options on Windows:
"bridge": "",
"fixed-cidr": "",
"raw-logs": false,
"allow-nondistributable-artifacts": [],
"registry-mirrors": [],
"insecure-registries": [],
"disable-legacy-registry": false
Expand Down Expand Up @@ -1361,6 +1390,7 @@ The list of currently supported options that can be reconfigured is this:
- `runtimes`: it updates the list of available OCI runtimes that can
be used to run containers
- `authorization-plugin`: specifies the authorization plugins to use.
- `allow-nondistributable-artifacts`: Replaces the set of registries to which the daemon will push nondistributable artifacts with a new set of registries.
- `insecure-registries`: it replaces the daemon insecure registries with a new set of insecure registries. If some existing insecure registries in daemon's configuration are not in newly reloaded insecure resgitries, these existing ones will be removed from daemon's config.
- `registry-mirrors`: it replaces the daemon registry mirrors with a new set of registry mirrors. If some existing registry mirrors in daemon's configuration are not in newly reloaded registry mirrors, these existing ones will be removed from daemon's config.

Expand Down
2 changes: 1 addition & 1 deletion integration-cli/docker_cli_events_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ func (s *DockerDaemonSuite) TestDaemonEvents(c *check.C) {
out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c))
c.Assert(err, checker.IsNil)

c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s (cluster-advertise=, cluster-store=, cluster-store-opts={}, debug=true, default-runtime=runc, default-shm-size=67108864, insecure-registries=[], labels=[\"bar=foo\"], live-restore=false, max-concurrent-downloads=1, max-concurrent-uploads=5, name=%s, registry-mirrors=[], runtimes=runc:{docker-runc []}, shutdown-timeout=10)", daemonID, daemonName))
c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s (allow-nondistributable-artifacts=[], cluster-advertise=, cluster-store=, cluster-store-opts={}, debug=true, default-runtime=runc, default-shm-size=67108864, insecure-registries=[], labels=[\"bar=foo\"], live-restore=false, max-concurrent-downloads=1, max-concurrent-uploads=5, name=%s, registry-mirrors=[], runtimes=runc:{docker-runc []}, shutdown-timeout=10)", daemonID, daemonName))
}

func (s *DockerDaemonSuite) TestDaemonEventsWithFilters(c *check.C) {
Expand Down
15 changes: 15 additions & 0 deletions man/dockerd.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dockerd - Enable daemon mode
# SYNOPSIS
**dockerd**
[**--add-runtime**[=*[]*]]
[**--allow-nondistributable-artifacts**[=*[]*]]
[**--api-cors-header**=[=*API-CORS-HEADER*]]
[**--authorization-plugin**[=*[]*]]
[**-b**|**--bridge**[=*BRIDGE*]]
Expand Down Expand Up @@ -116,6 +117,20 @@ $ sudo dockerd --add-runtime runc=runc --add-runtime custom=/usr/local/bin/my-ru

**Note**: defining runtime arguments via the command line is not supported.

**--allow-nondistributable-artifacts**=[]
Push nondistributable artifacts to the specified registries.

List can contain elements with CIDR notation to specify a whole subnet.

This option is useful when pushing images containing nondistributable
artifacts to a registry on an air-gapped network so hosts on that network can
pull the images without connecting to another server.

**Warning**: Nondistributable artifacts typically have restrictions on how
and where they can be distributed and shared. Only use this feature to push
artifacts to private registries and ensure that you are in compliance with
any terms that cover redistributing nondistributable artifacts.

**--api-cors-header**=""
Set CORS headers in the Engine API. Default is cors disabled. Give urls like
"http://foo, http://bar, ...". Give "*" to allow all.
Expand Down
Loading

0 comments on commit a30ef99

Please sign in to comment.