Make experimental a runtime flag

Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
This commit is contained in:
Kenfe-Mickael Laventure 2016-10-06 07:09:54 -07:00
parent 0ab13dda66
commit 7781a1bf0f
112 changed files with 782 additions and 979 deletions

View file

@ -0,0 +1,29 @@
package middleware
import (
"net/http"
"golang.org/x/net/context"
)
// ExperimentalMiddleware is a the middleware in charge of adding the
// 'Docker-Experimental' header to every outgoing request
type ExperimentalMiddleware struct {
experimental string
}
// NewExperimentalMiddleware creates a new ExperimentalMiddleware
func NewExperimentalMiddleware(experimentalEnabled bool) ExperimentalMiddleware {
if experimentalEnabled {
return ExperimentalMiddleware{"true"}
}
return ExperimentalMiddleware{"false"}
}
// WrapHandler returns a new handler function wrapping the previous one in the request chain.
func (e ExperimentalMiddleware) WrapHandler(handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
w.Header().Set("Docker-Experimental", e.experimental)
return handler(ctx, w, r, vars)
}
}

View file

@ -1,5 +1,3 @@
// +build experimental
package checkpoint
import "github.com/docker/docker/api/types"

View file

@ -26,3 +26,11 @@ func NewRouter(b Backend, decoder httputils.ContainerDecoder) router.Router {
func (r *checkpointRouter) Routes() []router.Route {
return r.routes
}
func (r *checkpointRouter) initRoutes() {
r.routes = []router.Route{
router.NewGetRoute("/containers/{name:.*}/checkpoints", r.getContainerCheckpoints),
router.NewPostRoute("/containers/{name:.*}/checkpoints", r.postContainerCheckpoint),
router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", r.deleteContainerCheckpoint),
}
}

View file

@ -1,15 +0,0 @@
// +build experimental
package checkpoint
import (
"github.com/docker/docker/api/server/router"
)
func (r *checkpointRouter) initRoutes() {
r.routes = []router.Route{
router.NewGetRoute("/containers/{name:.*}/checkpoints", r.getContainerCheckpoints),
router.NewPostRoute("/containers/{name:.*}/checkpoints", r.postContainerCheckpoint),
router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", r.deleteContainerCheckpoint),
}
}

View file

@ -1,8 +0,0 @@
// +build !experimental
package checkpoint
func (r *checkpointRouter) initRoutes() {}
// Backend is empty so that the package can compile in non-experimental
type Backend interface{}

View file

@ -1,5 +1,3 @@
// +build experimental
package checkpoint
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package plugin
import (

View file

@ -21,3 +21,16 @@ func NewRouter(b Backend) router.Router {
func (r *pluginRouter) Routes() []router.Route {
return r.routes
}
func (r *pluginRouter) initRoutes() {
r.routes = []router.Route{
router.NewGetRoute("/plugins", r.listPlugins),
router.NewGetRoute("/plugins/{name:.*}", r.inspectPlugin),
router.NewDeleteRoute("/plugins/{name:.*}", r.removePlugin),
router.NewPostRoute("/plugins/{name:.*}/enable", r.enablePlugin), // PATCH?
router.NewPostRoute("/plugins/{name:.*}/disable", r.disablePlugin),
router.NewPostRoute("/plugins/pull", r.pullPlugin),
router.NewPostRoute("/plugins/{name:.*}/push", r.pushPlugin),
router.NewPostRoute("/plugins/{name:.*}/set", r.setPlugin),
}
}

View file

@ -1,20 +0,0 @@
// +build experimental
package plugin
import (
"github.com/docker/docker/api/server/router"
)
func (r *pluginRouter) initRoutes() {
r.routes = []router.Route{
router.NewGetRoute("/plugins", r.listPlugins),
router.NewGetRoute("/plugins/{name:.*}", r.inspectPlugin),
router.NewDeleteRoute("/plugins/{name:.*}", r.removePlugin),
router.NewPostRoute("/plugins/{name:.*}/enable", r.enablePlugin), // PATCH?
router.NewPostRoute("/plugins/{name:.*}/disable", r.disablePlugin),
router.NewPostRoute("/plugins/pull", r.pullPlugin),
router.NewPostRoute("/plugins/{name:.*}/push", r.pushPlugin),
router.NewPostRoute("/plugins/{name:.*}/set", r.setPlugin),
}
}

View file

@ -1,9 +0,0 @@
// +build !experimental
package plugin
func (r *pluginRouter) initRoutes() {}
// Backend is empty so that the package can compile in non-experimental
// (Needed by volume driver)
type Backend interface{}

View file

@ -1,5 +1,3 @@
// +build experimental
package plugin
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package bundlefile
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package bundlefile
import (

View file

@ -1,13 +1,27 @@
// +build !experimental
package checkpoint
import (
"fmt"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
"github.com/spf13/cobra"
)
// NewCheckpointCommand returns the `checkpoint` subcommand (only in experimental)
func NewCheckpointCommand(dockerCli *command.DockerCli) *cobra.Command {
return &cobra.Command{}
cmd := &cobra.Command{
Use: "checkpoint",
Short: "Manage checkpoints",
Args: cli.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString())
},
}
cmd.AddCommand(
newCreateCommand(dockerCli),
newListCommand(dockerCli),
newRemoveCommand(dockerCli),
)
return cmd
}

View file

@ -1,30 +0,0 @@
// +build experimental
package checkpoint
import (
"fmt"
"github.com/spf13/cobra"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
)
// NewCheckpointCommand returns the `checkpoint` subcommand (only in experimental)
func NewCheckpointCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "checkpoint",
Short: "Manage checkpoints",
Args: cli.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString())
},
}
cmd.AddCommand(
newCreateCommand(dockerCli),
newListCommand(dockerCli),
newRemoveCommand(dockerCli),
)
return cmd
}

View file

@ -1,5 +1,3 @@
// +build experimental
package checkpoint
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package checkpoint
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package checkpoint
import (

View file

@ -19,6 +19,7 @@ import (
dopts "github.com/docker/docker/opts"
"github.com/docker/go-connections/sockets"
"github.com/docker/go-connections/tlsconfig"
"golang.org/x/net/context"
)
// Streams is an interface which exposes the standard input and output streams
@ -37,6 +38,21 @@ type DockerCli struct {
err io.Writer
keyFile string
client client.APIClient
hasExperimental *bool
}
// HasExperimental returns true if experimental features are accessible
func (cli *DockerCli) HasExperimental() bool {
if cli.hasExperimental == nil {
if cli.client == nil {
cli.Initialize(cliflags.NewClientOptions())
}
enabled := false
cli.hasExperimental = &enabled
enabled, _ = cli.client.Ping(context.Background())
}
return *cli.hasExperimental
}
// Client returns the APIClient

View file

@ -24,8 +24,6 @@ func AddCommands(cmd *cobra.Command, dockerCli *command.DockerCli) {
cmd.AddCommand(
node.NewNodeCommand(dockerCli),
service.NewServiceCommand(dockerCli),
stack.NewStackCommand(dockerCli),
stack.NewTopLevelDeployCommand(dockerCli),
swarm.NewSwarmCommand(dockerCli),
container.NewContainerCommand(dockerCli),
image.NewImageCommand(dockerCli),
@ -72,11 +70,19 @@ func AddCommands(cmd *cobra.Command, dockerCli *command.DockerCli) {
hide(image.NewSaveCommand(dockerCli)),
hide(image.NewTagCommand(dockerCli)),
hide(system.NewInspectCommand(dockerCli)),
)
if dockerCli.HasExperimental() {
cmd.AddCommand(
stack.NewStackCommand(dockerCli),
stack.NewTopLevelDeployCommand(dockerCli),
checkpoint.NewCheckpointCommand(dockerCli),
plugin.NewPluginCommand(dockerCli),
)
}
}
func hide(cmd *cobra.Command) *cobra.Command {
if os.Getenv("DOCKER_HIDE_LEGACY_COMMANDS") == "" {
return cmd

View file

@ -44,7 +44,9 @@ func NewStartCommand(dockerCli *command.DockerCli) *cobra.Command {
flags.BoolVarP(&opts.openStdin, "interactive", "i", false, "Attach container's STDIN")
flags.StringVar(&opts.detachKeys, "detach-keys", "", "Override the key sequence for detaching a container")
addExperimentalStartFlags(flags, &opts)
if dockerCli.HasExperimental() {
flags.StringVar(&opts.checkpoint, "checkpoint", "", "Restore from this checkpoint")
}
return cmd
}

View file

@ -1,8 +0,0 @@
// +build !experimental
package container
import "github.com/spf13/pflag"
func addExperimentalStartFlags(flags *pflag.FlagSet, opts *startOptions) {
}

View file

@ -1,9 +0,0 @@
// +build experimental
package container
import "github.com/spf13/pflag"
func addExperimentalStartFlags(flags *pflag.FlagSet, opts *startOptions) {
flags.StringVar(&opts.checkpoint, "checkpoint", "", "Restore from this checkpoint")
}

View file

@ -1,13 +1,33 @@
// +build !experimental
package plugin
import (
"fmt"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
"github.com/spf13/cobra"
)
// NewPluginCommand returns a cobra command for `plugin` subcommands
func NewPluginCommand(dockerCli *command.DockerCli) *cobra.Command {
return &cobra.Command{}
cmd := &cobra.Command{
Use: "plugin",
Short: "Manage plugins",
Args: cli.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString())
},
}
cmd.AddCommand(
newDisableCommand(dockerCli),
newEnableCommand(dockerCli),
newInspectCommand(dockerCli),
newInstallCommand(dockerCli),
newListCommand(dockerCli),
newRemoveCommand(dockerCli),
newSetCommand(dockerCli),
newPushCommand(dockerCli),
)
return cmd
}

View file

@ -1,35 +0,0 @@
// +build experimental
package plugin
import (
"fmt"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
"github.com/spf13/cobra"
)
// NewPluginCommand returns a cobra command for `plugin` subcommands
func NewPluginCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "plugin",
Short: "Manage plugins",
Args: cli.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString())
},
}
cmd.AddCommand(
newDisableCommand(dockerCli),
newEnableCommand(dockerCli),
newInspectCommand(dockerCli),
newInstallCommand(dockerCli),
newListCommand(dockerCli),
newRemoveCommand(dockerCli),
newSetCommand(dockerCli),
newPushCommand(dockerCli),
)
return cmd
}

View file

@ -1,5 +1,3 @@
// +build experimental
package plugin
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package plugin
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package plugin
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package plugin
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package plugin
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package plugin
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package plugin
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package plugin
import (

View file

@ -1,18 +1,38 @@
// +build !experimental
package stack
import (
"fmt"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
"github.com/spf13/cobra"
)
// NewStackCommand returns no command
// NewStackCommand returns a cobra command for `stack` subcommands
func NewStackCommand(dockerCli *command.DockerCli) *cobra.Command {
return &cobra.Command{}
cmd := &cobra.Command{
Use: "stack",
Short: "Manage Docker stacks",
Args: cli.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString())
},
}
cmd.AddCommand(
newConfigCommand(dockerCli),
newDeployCommand(dockerCli),
newListCommand(dockerCli),
newRemoveCommand(dockerCli),
newServicesCommand(dockerCli),
newPsCommand(dockerCli),
)
return cmd
}
// NewTopLevelDeployCommand returns no command
// NewTopLevelDeployCommand returns a command for `docker deploy`
func NewTopLevelDeployCommand(dockerCli *command.DockerCli) *cobra.Command {
return &cobra.Command{}
cmd := newDeployCommand(dockerCli)
// Remove the aliases at the top level
cmd.Aliases = []string{}
return cmd
}

View file

@ -1,40 +0,0 @@
// +build experimental
package stack
import (
"fmt"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
"github.com/spf13/cobra"
)
// NewStackCommand returns a cobra command for `stack` subcommands
func NewStackCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "stack",
Short: "Manage Docker stacks",
Args: cli.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString())
},
}
cmd.AddCommand(
newConfigCommand(dockerCli),
newDeployCommand(dockerCli),
newListCommand(dockerCli),
newRemoveCommand(dockerCli),
newServicesCommand(dockerCli),
newPsCommand(dockerCli),
)
return cmd
}
// NewTopLevelDeployCommand returns a command for `docker deploy`
func NewTopLevelDeployCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := newDeployCommand(dockerCli)
// Remove the aliases at the top level
cmd.Aliases = []string{}
return cmd
}

View file

@ -1,5 +1,3 @@
// +build experimental
package stack
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package stack
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package stack
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package stack
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package stack
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package stack
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package stack
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package stack
import (

View file

@ -225,7 +225,7 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
}
}
ioutils.FprintfIfTrue(dockerCli.Out(), "Experimental: %v\n", info.ExperimentalBuild)
fmt.Fprintf(dockerCli.Out(), "Experimental: %v\n", info.ExperimentalBuild)
if info.ClusterStore != "" {
fmt.Fprintf(dockerCli.Out(), "Cluster Store: %s\n", info.ClusterStore)
}

View file

@ -10,7 +10,6 @@ import (
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
"github.com/docker/docker/dockerversion"
"github.com/docker/docker/utils"
"github.com/docker/docker/utils/templates"
"github.com/spf13/cobra"
)
@ -21,8 +20,7 @@ var versionTemplate = `Client:
Go version: {{.Client.GoVersion}}
Git commit: {{.Client.GitCommit}}
Built: {{.Client.BuildTime}}
OS/Arch: {{.Client.Os}}/{{.Client.Arch}}{{if .Client.Experimental}}
Experimental: {{.Client.Experimental}}{{end}}{{if .ServerOK}}
OS/Arch: {{.Client.Os}}/{{.Client.Arch}}{{if .ServerOK}}
Server:
Version: {{.Server.Version}}
@ -30,8 +28,8 @@ Server:
Go version: {{.Server.GoVersion}}
Git commit: {{.Server.GitCommit}}
Built: {{.Server.BuildTime}}
OS/Arch: {{.Server.Os}}/{{.Server.Arch}}{{if .Server.Experimental}}
Experimental: {{.Server.Experimental}}{{end}}{{end}}`
OS/Arch: {{.Server.Os}}/{{.Server.Arch}}
Experimental: {{.Server.Experimental}}{{end}}`
type versionOptions struct {
format string
@ -80,7 +78,6 @@ func runVersion(dockerCli *command.DockerCli, opts *versionOptions) error {
BuildTime: dockerversion.BuildTime,
Os: runtime.GOOS,
Arch: runtime.GOARCH,
Experimental: utils.ExperimentalBuild(),
},
}

View file

@ -127,6 +127,7 @@ type SystemAPIClient interface {
Info(ctx context.Context) (types.Info, error)
RegistryLogin(ctx context.Context, auth types.AuthConfig) (types.AuthResponse, error)
DiskUsage(ctx context.Context) (types.DiskUsage, error)
Ping(ctx context.Context) (bool, error)
}
// VolumeAPIClient defines API client methods for the volumes

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (
@ -7,9 +5,7 @@ import (
"golang.org/x/net/context"
)
// APIClient is an interface that clients that talk with a docker server must implement.
type APIClient interface {
CommonAPIClient
type apiClientExperimental interface {
CheckpointAPIClient
PluginAPIClient
}
@ -32,6 +28,3 @@ type PluginAPIClient interface {
PluginSet(ctx context.Context, name string, args []string) error
PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error)
}
// Ensure that Client always implements APIClient.
var _ APIClient = &Client{}

View file

@ -1,10 +1,9 @@
// +build !experimental
package client
// APIClient is an interface that clients that talk with a docker server must implement.
type APIClient interface {
CommonAPIClient
apiClientExperimental
}
// Ensure that Client always implements APIClient.

19
client/ping.go Normal file
View file

@ -0,0 +1,19 @@
package client
import "golang.org/x/net/context"
// Ping pings the server and return the value of the "Docker-Experimental" header
func (cli *Client) Ping(ctx context.Context) (bool, error) {
serverResp, err := cli.get(ctx, "/_ping", nil, nil)
if err != nil {
return false, err
}
defer ensureReaderClosed(serverResp)
exp := serverResp.header.Get("Docker-Experimental")
if exp != "true" {
return false, nil
}
return true, nil
}

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -1,5 +1,3 @@
// +build experimental
package client
import (

View file

@ -91,12 +91,8 @@ func main() {
}
func showVersion() {
if utils.ExperimentalBuild() {
fmt.Printf("Docker version %s, build %s, experimental\n", dockerversion.Version, dockerversion.GitCommit)
} else {
fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit)
}
}
func dockerPreRun(opts *cliflags.ClientOptions) {
cliflags.SetLogLevel(opts.Common.LogLevel)

View file

@ -129,7 +129,7 @@ func (cli *DaemonCli) start(opts daemonOptions) (err error) {
utils.EnableDebug()
}
if utils.ExperimentalBuild() {
if cli.Config.Experimental {
logrus.Warn("Running experimental build")
}
@ -435,6 +435,9 @@ func initRouter(s *apiserver.Server, d *daemon.Daemon, c *cluster.Cluster) {
func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config) {
v := cfg.Version
exp := middleware.NewExperimentalMiddleware(cli.d.HasExperimental())
s.UseMiddleware(exp)
vm := middleware.NewVersionMiddleware(v, api.DefaultVersion, api.MinVersion)
s.UseMiddleware(vm)

View file

@ -13,7 +13,6 @@ import (
"github.com/docker/docker/dockerversion"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/docker/pkg/term"
"github.com/docker/docker/utils"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
@ -85,12 +84,8 @@ func runDaemon(opts daemonOptions) error {
}
func showVersion() {
if utils.ExperimentalBuild() {
fmt.Printf("Docker version %s, build %s, experimental\n", dockerversion.Version, dockerversion.GitCommit)
} else {
fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit)
}
}
func main() {
if reexec.Init() {

View file

@ -1,13 +0,0 @@
// +build !experimental
package main
import (
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/server/router"
"github.com/docker/docker/daemon"
)
func addExperimentalRouters(routers []router.Router, d *daemon.Daemon, decoder httputils.ContainerDecoder) []router.Router {
return routers
}

View file

@ -1,5 +1,3 @@
// +build experimental
package main
import (
@ -12,5 +10,8 @@ import (
)
func addExperimentalRouters(routers []router.Router, d *daemon.Daemon, decoder httputils.ContainerDecoder) []router.Router {
if !d.HasExperimental() {
return []router.Router{}
}
return append(routers, checkpointrouter.NewRouter(d, decoder), pluginrouter.NewRouter(plugin.GetManager()))
}

View file

@ -153,6 +153,8 @@ type CommonConfig struct {
reloadLock sync.Mutex
valuesSet map[string]interface{}
Experimental bool `json:"experimental"` // Experimental indicates whether experimental features should be exposed or not
}
// InstallCommonFlags adds flags to the pflag.FlagSet to configure the daemon
@ -187,6 +189,7 @@ func (config *Config) InstallCommonFlags(flags *pflag.FlagSet) {
flags.IntVar(&config.ShutdownTimeout, "shutdown-timeout", defaultShutdownTimeout, "Set the default shutdown timeout")
flags.StringVar(&config.SwarmDefaultAdvertiseAddr, "swarm-default-advertise-addr", "", "Set default address or interface for swarm advertised address")
flags.BoolVar(&config.Experimental, "experimental", false, "Enable experimental features")
config.MaxConcurrentDownloads = &maxConcurrentDownloads
config.MaxConcurrentUploads = &maxConcurrentUploads

View file

@ -1,5 +1,3 @@
// +build experimental
package daemon
import (

View file

@ -1,10 +0,0 @@
// +build !experimental
package daemon
import (
"github.com/spf13/pflag"
)
func (config *Config) attachExperimentalFlags(cmd *pflag.FlagSet) {
}

View file

@ -104,6 +104,14 @@ type Daemon struct {
clusterProvider cluster.Provider
}
// HasExperimental returns whether the experimental features of the daemon are enabled or not
func (daemon *Daemon) HasExperimental() bool {
if daemon.configStore != nil && daemon.configStore.Experimental {
return true
}
return false
}
func (daemon *Daemon) restore() error {
var (
currentDriver = daemon.GraphDriverName()
@ -667,7 +675,7 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
}
// Plugin system initialization should happen before restore. Do not change order.
if err := pluginInit(d, config, containerdRemote); err != nil {
if err := d.pluginInit(config, containerdRemote); err != nil {
return nil, err
}
@ -775,7 +783,7 @@ func (daemon *Daemon) Shutdown() error {
}
// Shutdown plugins after containers. Dont change the order.
pluginShutdown()
daemon.pluginShutdown()
// trigger libnetwork Stop only if it's initialized
if daemon.netController != nil {
@ -1022,7 +1030,6 @@ func (daemon *Daemon) Reload(config *Config) (err error) {
if err := daemon.containerdRemote.UpdateOptions(libcontainerd.WithLiveRestore(config.LiveRestoreEnabled)); err != nil {
return err
}
}
// If no value is set for max-concurrent-downloads we assume it is the default value

View file

@ -1,5 +1,3 @@
// +build experimental
package daemon
import (
@ -12,11 +10,17 @@ func (daemon *Daemon) verifyExperimentalContainerSettings(hostConfig *container.
return nil, nil
}
func pluginInit(d *Daemon, cfg *Config, remote libcontainerd.Remote) error {
return plugin.Init(cfg.Root, d.PluginStore, remote, d.RegistryService, cfg.LiveRestoreEnabled, d.LogPluginEvent)
func (daemon *Daemon) pluginInit(cfg *Config, remote libcontainerd.Remote) error {
if !daemon.HasExperimental() {
return nil
}
return plugin.Init(cfg.Root, daemon.PluginStore, remote, daemon.RegistryService, cfg.LiveRestoreEnabled, daemon.LogPluginEvent)
}
func pluginShutdown() {
func (daemon *Daemon) pluginShutdown() {
if !daemon.HasExperimental() {
return
}
manager := plugin.GetManager()
// Check for a valid manager object. In error conditions, daemon init can fail
// and shutdown called, before plugin manager is initialized.

View file

@ -1,19 +0,0 @@
// +build !experimental
package daemon
import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/libcontainerd"
)
func (daemon *Daemon) verifyExperimentalContainerSettings(hostConfig *container.HostConfig, config *container.Config) ([]string, error) {
return nil, nil
}
func pluginInit(d *Daemon, config *Config, remote libcontainerd.Remote) error {
return nil
}
func pluginShutdown() {
}

View file

@ -1,5 +1,3 @@
// +build experimental
package graphdriver
import (

View file

@ -1,9 +0,0 @@
// +build !experimental
package graphdriver
import "github.com/docker/docker/pkg/plugingetter"
func lookupPlugin(name, home string, opts []string, pg plugingetter.PluginGetter) (Driver, error) {
return nil, ErrNotSupported
}

View file

@ -1,5 +1,3 @@
// +build experimental
package graphdriver
import (

View file

@ -109,7 +109,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
MemTotal: meminfo.MemTotal,
DockerRootDir: daemon.configStore.Root,
Labels: daemon.configStore.Labels,
ExperimentalBuild: utils.ExperimentalBuild(),
ExperimentalBuild: daemon.configStore.Experimental,
ServerVersion: dockerversion.Version,
ClusterStore: daemon.configStore.ClusterStore,
ClusterAdvertise: daemon.configStore.ClusterAdvertise,
@ -158,7 +158,7 @@ func (daemon *Daemon) SystemVersion() types.Version {
Os: runtime.GOOS,
Arch: runtime.GOARCH,
BuildTime: dockerversion.BuildTime,
Experimental: utils.ExperimentalBuild(),
Experimental: daemon.configStore.Experimental,
}
kernelVersion := "<unknown>"

View file

@ -157,7 +157,7 @@ This section lists each version from latest to oldest. Each listing includes a
* `POST /containers/prune` prunes stopped containers.
* `POST /images/prune` prunes unused images.
* `POST /volumes/prune` prunes unused volumes.
* Every API response now includes a `Docker-Experimental` header specifying if experimental features are enabled (value can be `true` or `false`).
### v1.24 API changes

View file

@ -45,6 +45,7 @@ Options:
--dns-search value DNS search domains to use (default [])
--exec-opt value Runtime execution options (default [])
--exec-root string Root directory for execution state files (default "/var/run/docker")
--experimental Enable experimental features
--fixed-cidr string IPv4 subnet for fixed IPs
--fixed-cidr-v6 string IPv6 subnet for fixed IPs
-g, --graph string Root of the Docker runtime (default "/var/lib/docker")
@ -1114,6 +1115,7 @@ This is a full example of the allowed configuration options on Linux:
"dns-search": [],
"exec-opts": [],
"exec-root": "",
"experimental": false,
"storage-driver": "",
"storage-opts": [],
"labels": [],
@ -1195,6 +1197,7 @@ This is a full example of the allowed configuration options on Windows:
"dns-opts": [],
"dns-search": [],
"exec-opts": [],
"experimental": false,
"storage-driver": "",
"storage-opts": [],
"labels": [],

View file

@ -126,12 +126,6 @@ if [ ! "$GOPATH" ]; then
exit 1
fi
if [ "$DOCKER_EXPERIMENTAL" ]; then
echo >&2 '# WARNING! DOCKER_EXPERIMENTAL is set: building experimental features'
echo >&2
DOCKER_BUILDTAGS+=" experimental"
fi
DOCKER_BUILDTAGS+=" daemon"
if ${PKG_CONFIG} 'libsystemd >= 209' 2> /dev/null ; then
DOCKER_BUILDTAGS+=" journald"

View file

@ -50,6 +50,11 @@ if [ "$DOCKER_REMAP_ROOT" ]; then
extra_params="--userns-remap $DOCKER_REMAP_ROOT"
fi
if [ "$DOCKER_EXPERIMENTAL" ]; then
echo >&2 '# DOCKER_EXPERIMENTAL is set: starting daemon with experimental features enabled! '
extra_params="$extra_params --experimental"
fi
if [ -z "$DOCKER_TEST_HOST" ]; then
# Start apparmor if it is enabled
if [ -e "/sys/module/apparmor/parameters/enabled" ] && [ "$(cat /sys/module/apparmor/parameters/enabled)" == "Y" ]; then

View file

@ -76,10 +76,6 @@ set -e
# Install runc and containerd
RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic
EOF
if [ "$DOCKER_EXPERIMENTAL" ]; then
echo 'ENV DOCKER_EXPERIMENTAL 1' >> "$DEST/$version/Dockerfile.build"
fi
cat >> "$DEST/$version/Dockerfile.build" <<-EOF
RUN cp -aL hack/make/.build-deb debian
RUN { echo '$debSource (${debVersion}-0~${suite}) $suite; urgency=low'; echo; echo ' * Version: $VERSION'; echo; echo " -- $debMaintainer $debDate"; } > debian/changelog && cat >&2 debian/changelog

View file

@ -96,8 +96,7 @@ set -e
# Install runc and containerd
RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic
EOF
if [ "$DOCKER_EXPERIMENTAL" ]; then
if [[ "$VERSION" == *-dev ]] || [ -n "$(git status --porcelain)" ]; then
echo 'ENV DOCKER_EXPERIMENTAL 1' >> "$DEST/$version/Dockerfile.build"
fi
cat >> "$DEST/$version/Dockerfile.build" <<-EOF

View file

@ -39,7 +39,7 @@ if [[ "$VERSION" == *-rc* ]]; then
component="testing"
fi
if [ "$DOCKER_EXPERIMENTAL" ] || [[ "$VERSION" == *-dev ]] || [ -n "$(git status --porcelain)" ]; then
if [[ "$VERSION" == *-dev ]] || [ -n "$(git status --porcelain)" ]; then
component="experimental"
fi

View file

@ -25,7 +25,7 @@ if [[ "$VERSION" == *-rc* ]]; then
release="testing"
fi
if [ $DOCKER_EXPERIMENTAL ] || [[ "$VERSION" == *-dev ]] || [ -n "$(git status --porcelain)" ]; then
if [[ "$VERSION" == *-dev ]] || [ -n "$(git status --porcelain)" ]; then
release="experimental"
fi

View file

@ -266,7 +266,11 @@ func (s *DockerSwarmSuite) AddDaemon(c *check.C, joinSwarm, manager bool) *Swarm
port: defaultSwarmPort + s.portIndex,
}
d.listenAddr = fmt.Sprintf("0.0.0.0:%d", d.port)
err := d.StartWithBusybox("--iptables=false", "--swarm-default-advertise-addr=lo") // avoid networking conflicts
args := []string{"--iptables=false", "--swarm-default-advertise-addr=lo"} // avoid networking conflicts
if experimentalDaemon {
args = append(args, "--experimental")
}
err := d.StartWithBusybox(args...)
c.Assert(err, check.IsNil)
if joinSwarm == true {

View file

@ -153,6 +153,9 @@ func (d *Daemon) StartWithLogFile(out *os.File, providedArgs ...string) error {
"--pidfile", fmt.Sprintf("%s/docker.pid", d.folder),
fmt.Sprintf("--userland-proxy=%t", d.userlandProxy),
)
if experimentalDaemon {
args = append(args, "--experimental")
}
if !(d.useDefaultHost || d.useDefaultTLSHost) {
args = append(args, []string{"--host", d.sock()}...)
}

View file

@ -1,4 +1,4 @@
// +build linux, experimental
// +build linux
package main
@ -17,7 +17,8 @@ var pluginName = "tiborvass/no-remove"
// TestDaemonRestartWithPluginEnabled tests state restore for an enabled plugin
func (s *DockerDaemonSuite) TestDaemonRestartWithPluginEnabled(c *check.C) {
testRequires(c, Network)
testRequires(c, Network, ExperimentalDaemon)
if err := s.d.Start(); err != nil {
c.Fatalf("Could not start daemon: %v", err)
}
@ -49,7 +50,8 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithPluginEnabled(c *check.C) {
// TestDaemonRestartWithPluginDisabled tests state restore for a disabled plugin
func (s *DockerDaemonSuite) TestDaemonRestartWithPluginDisabled(c *check.C) {
testRequires(c, Network)
testRequires(c, Network, ExperimentalDaemon)
if err := s.d.Start(); err != nil {
c.Fatalf("Could not start daemon: %v", err)
}
@ -79,7 +81,8 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithPluginDisabled(c *check.C) {
// TestDaemonKillLiveRestoreWithPlugins SIGKILLs daemon started with --live-restore.
// Plugins should continue to run.
func (s *DockerDaemonSuite) TestDaemonKillLiveRestoreWithPlugins(c *check.C) {
testRequires(c, Network)
testRequires(c, Network, ExperimentalDaemon)
if err := s.d.Start("--live-restore"); err != nil {
c.Fatalf("Could not start daemon: %v", err)
}
@ -111,7 +114,8 @@ func (s *DockerDaemonSuite) TestDaemonKillLiveRestoreWithPlugins(c *check.C) {
// TestDaemonShutdownLiveRestoreWithPlugins SIGTERMs daemon started with --live-restore.
// Plugins should continue to run.
func (s *DockerDaemonSuite) TestDaemonShutdownLiveRestoreWithPlugins(c *check.C) {
testRequires(c, Network)
testRequires(c, Network, ExperimentalDaemon)
if err := s.d.Start("--live-restore"); err != nil {
c.Fatalf("Could not start daemon: %v", err)
}
@ -142,7 +146,8 @@ func (s *DockerDaemonSuite) TestDaemonShutdownLiveRestoreWithPlugins(c *check.C)
// TestDaemonShutdownWithPlugins shuts down running plugins.
func (s *DockerDaemonSuite) TestDaemonShutdownWithPlugins(c *check.C) {
testRequires(c, Network)
testRequires(c, Network, ExperimentalDaemon)
if err := s.d.Start(); err != nil {
c.Fatalf("Could not start daemon: %v", err)
}
@ -180,7 +185,8 @@ func (s *DockerDaemonSuite) TestDaemonShutdownWithPlugins(c *check.C) {
// TestVolumePlugin tests volume creation using a plugin.
func (s *DockerDaemonSuite) TestVolumePlugin(c *check.C) {
testRequires(c, Network)
testRequires(c, Network, ExperimentalDaemon)
volName := "plugin-volume"
volRoot := "/data"
destDir := "/tmp/data/"

View file

@ -1,21 +1,36 @@
// +build experimental
package main
import (
"strings"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
"strings"
)
func (s *DockerSuite) TestExperimentalVersion(c *check.C) {
func (s *DockerSuite) TestExperimentalVersionTrue(c *check.C) {
testRequires(c, ExperimentalDaemon)
out, _ := dockerCmd(c, "version")
for _, line := range strings.Split(out, "\n") {
if strings.HasPrefix(line, "Experimental (client):") || strings.HasPrefix(line, "Experimental (server):") {
if strings.HasPrefix(strings.TrimSpace(line), "Experimental:") {
c.Assert(line, checker.Matches, "*true")
return
}
}
out, _ = dockerCmd(c, "-v")
c.Assert(out, checker.Contains, ", experimental", check.Commentf("docker version did not contain experimental"))
c.Fatal(`"Experimental" not found in version output`)
}
func (s *DockerSuite) TestExperimentalVersionFalse(c *check.C) {
testRequires(c, NotExperimentalDaemon)
out, _ := dockerCmd(c, "version")
for _, line := range strings.Split(out, "\n") {
if strings.HasPrefix(strings.TrimSpace(line), "Experimental:") {
c.Assert(line, checker.Matches, "*false")
return
}
}
c.Fatal(`"Experimental" not found in version output`)
}

View file

@ -1,4 +1,3 @@
// +build experimental
// +build !windows
package main
@ -287,7 +286,7 @@ func (s *DockerExternalGraphdriverSuite) setUpPlugin(c *check.C, name string, ex
mux.HandleFunc("/GraphDriver.ApplyDiff", func(w http.ResponseWriter, r *http.Request) {
s.ec[ext].applydiff++
var diff io.Reader = r.Body
diff := r.Body
defer r.Body.Close()
id := r.URL.Query().Get("id")
@ -338,6 +337,8 @@ func (s *DockerExternalGraphdriverSuite) TearDownSuite(c *check.C) {
}
func (s *DockerExternalGraphdriverSuite) TestExternalGraphDriver(c *check.C) {
testRequires(c, ExperimentalDaemon)
s.testExternalGraphDriver("test-external-graph-driver", "spec", c)
s.testExternalGraphDriver("json-external-graph-driver", "json", c)
}
@ -388,7 +389,8 @@ func (s *DockerExternalGraphdriverSuite) testExternalGraphDriver(name string, ex
}
func (s *DockerExternalGraphdriverSuite) TestExternalGraphDriverPull(c *check.C) {
testRequires(c, Network)
testRequires(c, Network, ExperimentalDaemon)
c.Assert(s.d.Start(), check.IsNil)
out, err := s.d.Cmd("pull", "busybox:latest")

View file

@ -10,7 +10,6 @@ import (
"github.com/docker/docker/pkg/homedir"
"github.com/docker/docker/pkg/integration/checker"
icmd "github.com/docker/docker/pkg/integration/cmd"
"github.com/docker/docker/utils"
"github.com/go-check/check"
)
@ -117,7 +116,7 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
cmdsToTest = append(cmdsToTest, "network ls")
cmdsToTest = append(cmdsToTest, "network rm")
if utils.ExperimentalBuild() {
if experimentalDaemon {
cmdsToTest = append(cmdsToTest, "checkpoint create")
cmdsToTest = append(cmdsToTest, "checkpoint ls")
cmdsToTest = append(cmdsToTest, "checkpoint rm")

View file

@ -7,7 +7,6 @@ import (
"strings"
"github.com/docker/docker/pkg/integration/checker"
"github.com/docker/docker/utils"
"github.com/go-check/check"
)
@ -44,8 +43,10 @@ func (s *DockerSuite) TestInfoEnsureSucceeds(c *check.C) {
stringsToCheck = append(stringsToCheck, "Runtimes:", "Default Runtime: runc")
}
if utils.ExperimentalBuild() {
if experimentalDaemon {
stringsToCheck = append(stringsToCheck, "Experimental: true")
} else {
stringsToCheck = append(stringsToCheck, "Experimental: false")
}
for _, linePrefix := range stringsToCheck {

View file

@ -1,5 +1,3 @@
// +build experimental
package main
import (
@ -11,6 +9,7 @@ import (
)
func (s *DockerSwarmSuite) TestStackRemove(c *check.C) {
testRequires(c, ExperimentalDaemon)
d := s.AddDaemon(c, true, true)
stackArgs := append([]string{"stack", "remove", "UNKNOWN_STACK"})
@ -21,6 +20,7 @@ func (s *DockerSwarmSuite) TestStackRemove(c *check.C) {
}
func (s *DockerSwarmSuite) TestStackTasks(c *check.C) {
testRequires(c, ExperimentalDaemon)
d := s.AddDaemon(c, true, true)
stackArgs := append([]string{"stack", "ps", "UNKNOWN_STACK"})
@ -31,6 +31,7 @@ func (s *DockerSwarmSuite) TestStackTasks(c *check.C) {
}
func (s *DockerSwarmSuite) TestStackServices(c *check.C) {
testRequires(c, ExperimentalDaemon)
d := s.AddDaemon(c, true, true)
stackArgs := append([]string{"stack", "services", "UNKNOWN_STACK"})
@ -59,6 +60,7 @@ const testDAB = `{
}`
func (s *DockerSwarmSuite) TestStackWithDAB(c *check.C) {
testRequires(c, ExperimentalDaemon)
// setup
testStackName := "test"
testDABFileName := testStackName + ".dab"
@ -92,6 +94,7 @@ func (s *DockerSwarmSuite) TestStackWithDAB(c *check.C) {
}
func (s *DockerSwarmSuite) TestStackWithDABExtension(c *check.C) {
testRequires(c, ExperimentalDaemon)
// setup
testStackName := "test.dab"
testDABFileName := testStackName

View file

@ -1,4 +1,4 @@
// +build experimental
// +build !windows
package main
@ -50,7 +50,8 @@ var (
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanPersistance(c *check.C) {
// verify the driver automatically provisions the 802.1q link (dm-dummy0.60)
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker macvlan'
master := "dm-dummy0"
// simulate the master link the vlan tagged subinterface parent link will use
@ -69,7 +70,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanPersistance(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanPersistance(c *check.C) {
// verify the driver automatically provisions the 802.1q link (di-dummy0.70)
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'di' notation represent 'docker ipvlan'
master := "di-dummy0"
// simulate the master link the vlan tagged subinterface parent link will use
@ -88,7 +89,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanPersistance(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanSubIntCreate(c *check.C) {
// verify the driver automatically provisions the 802.1q link (dm-dummy0.50)
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker macvlan'
master := "dm-dummy0"
// simulate the master link the vlan tagged subinterface parent link will use
@ -103,7 +104,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanSubIntCreate(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanSubIntCreate(c *check.C) {
// verify the driver automatically provisions the 802.1q link (di-dummy0.50)
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker ipvlan'
master := "di-dummy0"
// simulate the master link the vlan tagged subinterface parent link will use
@ -118,7 +119,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanSubIntCreate(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanOverlapParent(c *check.C) {
// verify the same parent interface cannot be used if already in use by an existing network
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker macvlan'
master := "dm-dummy0"
out, err := createMasterDummy(c, master)
@ -138,7 +139,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanOverlapParent(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanOverlapParent(c *check.C) {
// verify the same parent interface cannot be used if already in use by an existing network
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker ipvlan'
master := "di-dummy0"
out, err := createMasterDummy(c, master)
@ -158,7 +159,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanOverlapParent(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanMultiSubnet(c *check.C) {
// create a dual stack multi-subnet Macvlan bridge mode network and validate connectivity between four containers, two on each subnet
testRequires(c, DaemonIsLinux, IPv6, MacvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, IPv6, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=macvlan", "--ipv6", "--subnet=172.28.100.0/24", "--subnet=172.28.102.0/24", "--gateway=172.28.102.254",
"--subnet=2001:db8:abc2::/64", "--subnet=2001:db8:abc4::/64", "--gateway=2001:db8:abc4::254", "dualstackbridge")
// Ensure the network was created
@ -213,7 +214,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanMultiSubnet(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL2MultiSubnet(c *check.C) {
// create a dual stack multi-subnet Ipvlan L2 network and validate connectivity within the subnets, two on each subnet
testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--ipv6", "--subnet=172.28.200.0/24", "--subnet=172.28.202.0/24", "--gateway=172.28.202.254",
"--subnet=2001:db8:abc8::/64", "--subnet=2001:db8:abc6::/64", "--gateway=2001:db8:abc6::254", "dualstackl2")
// Ensure the network was created
@ -267,7 +268,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL2MultiSubnet(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL3MultiSubnet(c *check.C) {
// create a dual stack multi-subnet Ipvlan L3 network and validate connectivity between all four containers per L3 mode
testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm, IPv6)
testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm, IPv6, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--ipv6", "--subnet=172.28.10.0/24", "--subnet=172.28.12.0/24", "--gateway=172.28.12.254",
"--subnet=2001:db8:abc9::/64", "--subnet=2001:db8:abc7::/64", "--gateway=2001:db8:abc7::254", "-o", "ipvlan_mode=l3", "dualstackl3")
// Ensure the network was created
@ -326,7 +327,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL3MultiSubnet(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanAddressing(c *check.C) {
// Ensure the default gateways, next-hops and default dev devices are properly set
testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=macvlan", "--ipv6", "--subnet=172.28.130.0/24",
"--subnet=2001:db8:abca::/64", "--gateway=2001:db8:abca::254", "-o", "macvlan_mode=bridge", "dualstackbridge")
assertNwIsAvailable(c, "dualstackbridge")
@ -372,7 +373,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanAddressing(c *check.C) {
func (s *DockerSuite) TestDockerNetworkMacVlanBridgeNilParent(c *check.C) {
// macvlan bridge mode - dummy parent interface is provisioned dynamically
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=macvlan", "dm-nil-parent")
assertNwIsAvailable(c, "dm-nil-parent")
@ -389,7 +390,7 @@ func (s *DockerSuite) TestDockerNetworkMacVlanBridgeNilParent(c *check.C) {
func (s *DockerSuite) TestDockerNetworkMacVlanBridgeInternalMode(c *check.C) {
// macvlan bridge mode --internal containers can communicate inside the network but not externally
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=macvlan", "--internal", "dm-internal")
assertNwIsAvailable(c, "dm-internal")
nr := getNetworkResource(c, "dm-internal")
@ -412,7 +413,7 @@ func (s *DockerSuite) TestDockerNetworkMacVlanBridgeInternalMode(c *check.C) {
func (s *DockerSuite) TestDockerNetworkIpvlanL2NilParent(c *check.C) {
// ipvlan l2 mode - dummy parent interface is provisioned dynamically
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "di-nil-parent")
assertNwIsAvailable(c, "di-nil-parent")
@ -429,7 +430,7 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL2NilParent(c *check.C) {
func (s *DockerSuite) TestDockerNetworkIpvlanL2InternalMode(c *check.C) {
// ipvlan l2 mode --internal containers can communicate inside the network but not externally
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--internal", "di-internal")
assertNwIsAvailable(c, "di-internal")
nr := getNetworkResource(c, "di-internal")
@ -451,7 +452,7 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL2InternalMode(c *check.C) {
func (s *DockerSuite) TestDockerNetworkIpvlanL3NilParent(c *check.C) {
// ipvlan l3 mode - dummy parent interface is provisioned dynamically
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.230.0/24",
"--subnet=172.28.220.0/24", "-o", "ipvlan_mode=l3", "di-nil-parent-l3")
assertNwIsAvailable(c, "di-nil-parent-l3")
@ -469,7 +470,7 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL3NilParent(c *check.C) {
func (s *DockerSuite) TestDockerNetworkIpvlanL3InternalMode(c *check.C) {
// ipvlan l3 mode --internal containers can communicate inside the network but not externally
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.230.0/24",
"--subnet=172.28.220.0/24", "-o", "ipvlan_mode=l3", "--internal", "di-internal-l3")
assertNwIsAvailable(c, "di-internal-l3")
@ -492,7 +493,7 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL3InternalMode(c *check.C) {
func (s *DockerSuite) TestDockerNetworkMacVlanExistingParent(c *check.C) {
// macvlan bridge mode - empty parent interface containers can reach each other internally but not externally
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
netName := "dm-parent-exists"
out, err := createMasterDummy(c, "dm-dummy0")
//out, err := createVlanInterface(c, "dm-parent", "dm-slave", "macvlan", "bridge")
@ -512,7 +513,7 @@ func (s *DockerSuite) TestDockerNetworkMacVlanExistingParent(c *check.C) {
func (s *DockerSuite) TestDockerNetworkMacVlanSubinterface(c *check.C) {
// macvlan bridge mode - empty parent interface containers can reach each other internally but not externally
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm)
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
netName := "dm-subinterface"
out, err := createMasterDummy(c, "dm-dummy0")
c.Assert(err, check.IsNil, check.Commentf(out))

View file

@ -61,6 +61,10 @@ var (
volumesConfigPath string
containerStoragePath string
// experimentalDaemon tell whether the main daemon has
// experimental features enabled or not
experimentalDaemon bool
// daemonStorageDriver is held globally so that tests can know the storage
// driver of the daemon. This is initialized in docker_utils by sending
// a version call to the daemon and examining the response header.
@ -129,12 +133,14 @@ func init() {
dockerBasePath = "/var/lib/docker"
type Info struct {
DockerRootDir string
ExperimentalBuild bool
}
var i Info
status, b, err := sockRequest("GET", "/info", nil)
if err == nil && status == 200 {
if err = json.Unmarshal(b, &i); err == nil {
dockerBasePath = i.DockerRootDir
experimentalDaemon = i.ExperimentalBuild
}
}
volumesConfigPath = dockerBasePath + "/volumes"

View file

@ -9,7 +9,6 @@ import (
"strings"
"time"
"github.com/docker/docker/utils"
"github.com/go-check/check"
)
@ -31,11 +30,11 @@ var (
"Test requires a Linux daemon",
}
ExperimentalDaemon = testRequirement{
func() bool { return utils.ExperimentalBuild() },
func() bool { return experimentalDaemon },
"Test requires an experimental daemon",
}
NotExperimentalDaemon = testRequirement{
func() bool { return !utils.ExperimentalBuild() },
func() bool { return !experimentalDaemon },
"Test requires a non experimental daemon",
}
IsAmd64 = testRequirement{

View file

@ -27,6 +27,7 @@ dockerd - Enable daemon mode
[**--dns-search**[=*[]*]]
[**--exec-opt**[=*[]*]]
[**--exec-root**[=*/var/run/docker*]]
[**--experimental**[=*false*]]
[**--fixed-cidr**[=*FIXED-CIDR*]]
[**--fixed-cidr-v6**[=*FIXED-CIDR-V6*]]
[**-G**|**--group**[=*docker*]]
@ -146,6 +147,9 @@ format.
**--exec-root**=""
Path to use as the root of the Docker execution state files. Default is `/var/run/docker`.
**--experimental**=""
Enable the daemon experimental features.
**--fixed-cidr**=""
IPv4 subnet for fixed IPs (e.g., 10.20.0.0/16); this subnet must be nested in the bridge subnet (which is defined by \-b or \-\-bip)

View file

@ -1,5 +1,3 @@
// +build experimental
package plugin
import (

Some files were not shown because too many files have changed in this diff Show more