Signed-off-by: Anda Xu <anda.xu@docker.com>
| ... | ... |
@@ -1,17 +1,21 @@ |
| 1 | 1 |
package build // import "github.com/docker/docker/api/server/router/build" |
| 2 | 2 |
|
| 3 |
-import "github.com/docker/docker/api/server/router" |
|
| 3 |
+import ( |
|
| 4 |
+ "github.com/docker/docker/api/server/router" |
|
| 5 |
+ "github.com/docker/docker/api/types" |
|
| 6 |
+) |
|
| 4 | 7 |
|
| 5 | 8 |
// buildRouter is a router to talk with the build controller |
| 6 | 9 |
type buildRouter struct {
|
| 7 |
- backend Backend |
|
| 8 |
- daemon experimentalProvider |
|
| 9 |
- routes []router.Route |
|
| 10 |
+ backend Backend |
|
| 11 |
+ daemon experimentalProvider |
|
| 12 |
+ routes []router.Route |
|
| 13 |
+ builderVersion types.BuilderVersion |
|
| 10 | 14 |
} |
| 11 | 15 |
|
| 12 | 16 |
// NewRouter initializes a new build router |
| 13 |
-func NewRouter(b Backend, d experimentalProvider) router.Router {
|
|
| 14 |
- r := &buildRouter{backend: b, daemon: d}
|
|
| 17 |
+func NewRouter(b Backend, d experimentalProvider, bv types.BuilderVersion) router.Router {
|
|
| 18 |
+ r := &buildRouter{backend: b, daemon: d, builderVersion: bv}
|
|
| 15 | 19 |
r.initRoutes() |
| 16 | 20 |
return r |
| 17 | 21 |
} |
| ... | ... |
@@ -230,8 +230,10 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r * |
| 230 | 230 |
return errdefs.InvalidParameter(errors.New("squash is only supported with experimental mode"))
|
| 231 | 231 |
} |
| 232 | 232 |
|
| 233 |
- if buildOptions.Version == types.BuilderBuildKit && !br.daemon.HasExperimental() {
|
|
| 234 |
- return errdefs.InvalidParameter(errors.New("buildkit is only supported with experimental mode"))
|
|
| 233 |
+ // check if the builder feature has been enabled from daemon as well. |
|
| 234 |
+ if buildOptions.Version == types.BuilderBuildKit && |
|
| 235 |
+ (br.builderVersion != types.BuilderBuildKit || !br.daemon.HasExperimental()) {
|
|
| 236 |
+ return errdefs.InvalidParameter(errors.New("buildkit is not enabled on daemon"))
|
|
| 235 | 237 |
} |
| 236 | 238 |
|
| 237 | 239 |
out := io.Writer(output) |
| ... | ... |
@@ -2,6 +2,7 @@ package system // import "github.com/docker/docker/api/server/router/system" |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"github.com/docker/docker/api/server/router" |
| 5 |
+ "github.com/docker/docker/api/types" |
|
| 5 | 6 |
buildkit "github.com/docker/docker/builder/builder-next" |
| 6 | 7 |
"github.com/docker/docker/builder/fscache" |
| 7 | 8 |
) |
| ... | ... |
@@ -9,25 +10,27 @@ import ( |
| 9 | 9 |
// systemRouter provides information about the Docker system overall. |
| 10 | 10 |
// It gathers information about host, daemon and container events. |
| 11 | 11 |
type systemRouter struct {
|
| 12 |
- backend Backend |
|
| 13 |
- cluster ClusterBackend |
|
| 14 |
- routes []router.Route |
|
| 15 |
- fscache *fscache.FSCache // legacy |
|
| 16 |
- builder *buildkit.Builder |
|
| 12 |
+ backend Backend |
|
| 13 |
+ cluster ClusterBackend |
|
| 14 |
+ routes []router.Route |
|
| 15 |
+ fscache *fscache.FSCache // legacy |
|
| 16 |
+ builder *buildkit.Builder |
|
| 17 |
+ builderVersion types.BuilderVersion |
|
| 17 | 18 |
} |
| 18 | 19 |
|
| 19 | 20 |
// NewRouter initializes a new system router |
| 20 |
-func NewRouter(b Backend, c ClusterBackend, fscache *fscache.FSCache, builder *buildkit.Builder) router.Router {
|
|
| 21 |
+func NewRouter(b Backend, c ClusterBackend, fscache *fscache.FSCache, builder *buildkit.Builder, bv types.BuilderVersion) router.Router {
|
|
| 21 | 22 |
r := &systemRouter{
|
| 22 |
- backend: b, |
|
| 23 |
- cluster: c, |
|
| 24 |
- fscache: fscache, |
|
| 25 |
- builder: builder, |
|
| 23 |
+ backend: b, |
|
| 24 |
+ cluster: c, |
|
| 25 |
+ fscache: fscache, |
|
| 26 |
+ builder: builder, |
|
| 27 |
+ builderVersion: bv, |
|
| 26 | 28 |
} |
| 27 | 29 |
|
| 28 | 30 |
r.routes = []router.Route{
|
| 29 | 31 |
router.NewOptionsRoute("/{anyroute:.*}", optionsHandler),
|
| 30 |
- router.NewGetRoute("/_ping", pingHandler),
|
|
| 32 |
+ router.NewGetRoute("/_ping", r.pingHandler),
|
|
| 31 | 33 |
router.NewGetRoute("/events", r.getEvents, router.WithCancel),
|
| 32 | 34 |
router.NewGetRoute("/info", r.getInfo),
|
| 33 | 35 |
router.NewGetRoute("/version", r.getVersion),
|
| ... | ... |
@@ -25,7 +25,10 @@ func optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, |
| 25 | 25 |
return nil |
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 |
-func pingHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
|
| 28 |
+func (s *systemRouter) pingHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
|
| 29 |
+ if bv := s.builderVersion; bv != "" {
|
|
| 30 |
+ w.Header().Set("Builder-Version", string(bv))
|
|
| 31 |
+ } |
|
| 29 | 32 |
_, err := w.Write([]byte{'O', 'K'})
|
| 30 | 33 |
return err |
| 31 | 34 |
} |
| ... | ... |
@@ -6972,6 +6972,9 @@ paths: |
| 6972 | 6972 |
API-Version: |
| 6973 | 6973 |
type: "string" |
| 6974 | 6974 |
description: "Max API Version the server supports" |
| 6975 |
+ BuildKit-Version: |
|
| 6976 |
+ type: "string" |
|
| 6977 |
+ description: "Default version of docker image builder" |
|
| 6975 | 6978 |
Docker-Experimental: |
| 6976 | 6979 |
type: "boolean" |
| 6977 | 6980 |
description: "If the server is running with experimental mode enabled" |
| ... | ... |
@@ -102,9 +102,10 @@ type ContainerStats struct {
|
| 102 | 102 |
// Ping contains response of Engine API: |
| 103 | 103 |
// GET "/_ping" |
| 104 | 104 |
type Ping struct {
|
| 105 |
- APIVersion string |
|
| 106 |
- OSType string |
|
| 107 |
- Experimental bool |
|
| 105 |
+ APIVersion string |
|
| 106 |
+ OSType string |
|
| 107 |
+ Experimental bool |
|
| 108 |
+ BuilderVersion BuilderVersion |
|
| 108 | 109 |
} |
| 109 | 110 |
|
| 110 | 111 |
// ComponentVersion describes the version information for a specific component. |
| ... | ... |
@@ -7,7 +7,7 @@ import ( |
| 7 | 7 |
"github.com/docker/docker/api/types" |
| 8 | 8 |
) |
| 9 | 9 |
|
| 10 |
-// Ping pings the server and returns the value of the "Docker-Experimental", "OS-Type" & "API-Version" headers |
|
| 10 |
+// Ping pings the server and returns the value of the "Docker-Experimental", "Builder-Version", "OS-Type" & "API-Version" headers |
|
| 11 | 11 |
func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
|
| 12 | 12 |
var ping types.Ping |
| 13 | 13 |
req, err := cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil)
|
| ... | ... |
@@ -27,6 +27,9 @@ func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
|
| 27 | 27 |
ping.Experimental = true |
| 28 | 28 |
} |
| 29 | 29 |
ping.OSType = serverResp.header.Get("OSType")
|
| 30 |
+ if bv := serverResp.header.Get("Builder-Version"); bv != "" {
|
|
| 31 |
+ ping.BuilderVersion = types.BuilderVersion(bv) |
|
| 32 |
+ } |
|
| 30 | 33 |
} |
| 31 | 34 |
return ping, cli.checkResponseErr(serverResp) |
| 32 | 35 |
} |
| ... | ... |
@@ -65,7 +65,6 @@ func installCommonConfigFlags(conf *config.Config, flags *pflag.FlagSet) {
|
| 65 | 65 |
|
| 66 | 66 |
flags.StringVar(&conf.SwarmDefaultAdvertiseAddr, "swarm-default-advertise-addr", "", "Set default address or interface for swarm advertised address") |
| 67 | 67 |
flags.BoolVar(&conf.Experimental, "experimental", false, "Enable experimental features") |
| 68 |
- |
|
| 69 | 68 |
flags.StringVar(&conf.MetricsAddress, "metrics-addr", "", "Set default address and port to serve the metrics api on") |
| 70 | 69 |
|
| 71 | 70 |
flags.Var(opts.NewNamedListOptsRef("node-generic-resources", &conf.NodeGenericResources, opts.ValidateSingleGenericResource), "node-generic-resource", "Advertise user-defined resource")
|
| ... | ... |
@@ -27,6 +27,7 @@ import ( |
| 27 | 27 |
swarmrouter "github.com/docker/docker/api/server/router/swarm" |
| 28 | 28 |
systemrouter "github.com/docker/docker/api/server/router/system" |
| 29 | 29 |
"github.com/docker/docker/api/server/router/volume" |
| 30 |
+ "github.com/docker/docker/api/types" |
|
| 30 | 31 |
buildkit "github.com/docker/docker/builder/builder-next" |
| 31 | 32 |
"github.com/docker/docker/builder/dockerfile" |
| 32 | 33 |
"github.com/docker/docker/builder/fscache" |
| ... | ... |
@@ -253,6 +254,7 @@ type routerOptions struct {
|
| 253 | 253 |
buildBackend *buildbackend.Backend |
| 254 | 254 |
buildCache *fscache.FSCache // legacy |
| 255 | 255 |
buildkit *buildkit.Builder |
| 256 |
+ builderVersion types.BuilderVersion |
|
| 256 | 257 |
daemon *daemon.Daemon |
| 257 | 258 |
api *apiserver.Server |
| 258 | 259 |
cluster *cluster.Cluster |
| ... | ... |
@@ -283,8 +285,7 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio |
| 283 | 283 |
if err != nil {
|
| 284 | 284 |
return opts, err |
| 285 | 285 |
} |
| 286 |
- |
|
| 287 |
- buildkit, err := buildkit.New(buildkit.Opt{
|
|
| 286 |
+ bk, err := buildkit.New(buildkit.Opt{
|
|
| 288 | 287 |
SessionManager: sm, |
| 289 | 288 |
Root: filepath.Join(config.Root, "buildkit"), |
| 290 | 289 |
Dist: daemon.DistributionServices(), |
| ... | ... |
@@ -293,16 +294,24 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio |
| 293 | 293 |
return opts, err |
| 294 | 294 |
} |
| 295 | 295 |
|
| 296 |
- bb, err := buildbackend.NewBackend(daemon.ImageService(), manager, buildCache, buildkit) |
|
| 296 |
+ bb, err := buildbackend.NewBackend(daemon.ImageService(), manager, buildCache, bk) |
|
| 297 | 297 |
if err != nil {
|
| 298 | 298 |
return opts, errors.Wrap(err, "failed to create buildmanager") |
| 299 | 299 |
} |
| 300 |
- |
|
| 300 |
+ var bv types.BuilderVersion |
|
| 301 |
+ if v, ok := config.Features["buildkit"]; ok {
|
|
| 302 |
+ if v {
|
|
| 303 |
+ bv = types.BuilderBuildKit |
|
| 304 |
+ } else {
|
|
| 305 |
+ bv = types.BuilderV1 |
|
| 306 |
+ } |
|
| 307 |
+ } |
|
| 301 | 308 |
return routerOptions{
|
| 302 | 309 |
sessionManager: sm, |
| 303 | 310 |
buildBackend: bb, |
| 304 | 311 |
buildCache: buildCache, |
| 305 |
- buildkit: buildkit, |
|
| 312 |
+ buildkit: bk, |
|
| 313 |
+ builderVersion: bv, |
|
| 306 | 314 |
daemon: daemon, |
| 307 | 315 |
}, nil |
| 308 | 316 |
} |
| ... | ... |
@@ -476,9 +485,9 @@ func initRouter(opts routerOptions) {
|
| 476 | 476 |
checkpointrouter.NewRouter(opts.daemon, decoder), |
| 477 | 477 |
container.NewRouter(opts.daemon, decoder), |
| 478 | 478 |
image.NewRouter(opts.daemon.ImageService()), |
| 479 |
- systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache, opts.buildkit), |
|
| 479 |
+ systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache, opts.buildkit, opts.builderVersion), |
|
| 480 | 480 |
volume.NewRouter(opts.daemon.VolumesService()), |
| 481 |
- build.NewRouter(opts.buildBackend, opts.daemon), |
|
| 481 |
+ build.NewRouter(opts.buildBackend, opts.daemon, opts.builderVersion), |
|
| 482 | 482 |
sessionrouter.NewRouter(opts.sessionManager), |
| 483 | 483 |
swarmrouter.NewRouter(opts.cluster), |
| 484 | 484 |
pluginrouter.NewRouter(opts.daemon.PluginManager()), |
| ... | ... |
@@ -56,6 +56,13 @@ var flatOptions = map[string]bool{
|
| 56 | 56 |
"default-ulimits": true, |
| 57 | 57 |
} |
| 58 | 58 |
|
| 59 |
+// skipValidateOptions contains configuration keys |
|
| 60 |
+// that will be skipped from findConfigurationConflicts |
|
| 61 |
+// for unknown flag validation. |
|
| 62 |
+var skipValidateOptions = map[string]bool{
|
|
| 63 |
+ "features": true, |
|
| 64 |
+} |
|
| 65 |
+ |
|
| 59 | 66 |
// LogConfig represents the default log configuration. |
| 60 | 67 |
// It includes json tags to deserialize configuration from a file |
| 61 | 68 |
// using the same names that the flags in the command line use. |
| ... | ... |
@@ -203,6 +210,10 @@ type CommonConfig struct {
|
| 203 | 203 |
// should be configured with the CRI plugin enabled. This allows using |
| 204 | 204 |
// Docker's containerd instance directly with a Kubernetes kubelet. |
| 205 | 205 |
CriContainerd bool `json:"cri-containerd,omitempty"` |
| 206 |
+ |
|
| 207 |
+ // Features contains a list of feature key value pairs indicating what features are enabled or disabled. |
|
| 208 |
+ // If a certain feature doesn't appear in this list then it's unset (i.e. neither true nor false). |
|
| 209 |
+ Features map[string]bool `json:"features,omitempty"` |
|
| 206 | 210 |
} |
| 207 | 211 |
|
| 208 | 212 |
// IsValueSet returns true if a configuration value |
| ... | ... |
@@ -444,7 +455,7 @@ func findConfigurationConflicts(config map[string]interface{}, flags *pflag.Flag
|
| 444 | 444 |
// 1. Search keys from the file that we don't recognize as flags. |
| 445 | 445 |
unknownKeys := make(map[string]interface{})
|
| 446 | 446 |
for key, value := range config {
|
| 447 |
- if flag := flags.Lookup(key); flag == nil {
|
|
| 447 |
+ if flag := flags.Lookup(key); flag == nil && !skipValidateOptions[key] {
|
|
| 448 | 448 |
unknownKeys[key] = value |
| 449 | 449 |
} |
| 450 | 450 |
} |