func TestVersionMiddlewareWithErrors(t *testing.T) { handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if httputils.VersionFromContext(ctx) == "" { t.Fatalf("Expected version, got empty string") } return nil } defaultVersion := version.Version("1.10.0") minVersion := version.Version("1.2.0") m := NewVersionMiddleware(defaultVersion.String(), defaultVersion, minVersion) h := m(handler) req, _ := http.NewRequest("GET", "/containers/json", nil) resp := httptest.NewRecorder() ctx := context.Background() vars := map[string]string{"version": "0.1"} err := h(ctx, resp, req, vars) if !strings.Contains(err.Error(), "client version 0.1 is too old. Minimum supported API version is 1.2.0") { t.Fatalf("Expected too old client error, got %v", err) } vars["version"] = "100000" err = h(ctx, resp, req, vars) if !strings.Contains(err.Error(), "client is newer than server") { t.Fatalf("Expected client newer than server error, got %v", err) } }
func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, enableCors bool, dockerVersion version.Version) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // log the request utils.Debugf("Calling %s %s", localMethod, localRoute) if logging { log.Println(r.Method, r.RequestURI) } if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") { userAgent := strings.Split(r.Header.Get("User-Agent"), "/") if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) { utils.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion) } } version := version.Version(mux.Vars(r)["version"]) if version == "" { version = api.APIVERSION } if enableCors { writeCorsHeaders(w, r) } if version.GreaterThan(api.APIVERSION) { http.Error(w, fmt.Errorf("client and server don't have same version (client : %s, server: %s)", version, api.APIVERSION).Error(), http.StatusNotFound) return } if err := handlerFunc(eng, version, w, r, mux.Vars(r)); err != nil { utils.Errorf("Handler for %s %s returned error: %s", localMethod, localRoute, err) httpError(w, err) } } }
// Update API Version in apiClient func (e *Engine) updateClientVersionFromServer(serverVersion string) { // v will be >= 1.8, since this is checked earlier v := version.Version(serverVersion) switch { case v.LessThan(version.Version("1.9")): e.apiClient.UpdateClientVersion("1.20") case v.LessThan(version.Version("1.10")): e.apiClient.UpdateClientVersion("1.21") case v.LessThan(version.Version("1.11")): e.apiClient.UpdateClientVersion("1.22") default: e.apiClient.UpdateClientVersion("1.23") } }
func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion string) (*mux.Router, error) { r := mux.NewRouter() if os.Getenv("DEBUG") != "" { AttachProfiler(r) } for method, routes := range ServerRoutes { for route, fct := range routes { log.Debugf("Registering %s, %s", method, route) // NOTE: scope issue, make sure the variables are local and won't be changed localRoute := route localFct := fct localMethod := method // build the handler function f := makeHttpHandler(eng, logging, localMethod, localRoute, localFct, enableCors, version.Version(dockerVersion)) // add the new route if localRoute == "" { r.Methods(localMethod).HandlerFunc(f) } else { r.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(f) r.Path(localRoute).Methods(localMethod).HandlerFunc(f) } } } return r, nil }
func TestContext(t *testing.T) { ctx := Background() // First make sure getting non-existent values doesn't break if id := ctx.RequestID(); id != "" { t.Fatalf("RequestID() should have been '', was: %q", id) } if ver := ctx.Version(); ver != "" { t.Fatalf("Version() should have been '', was: %q", ver) } // Test basic set/get ctx = WithValue(ctx, RequestID, "123") if ctx.RequestID() != "123" { t.Fatalf("RequestID() should have been '123'") } // Now make sure after a 2nd set we can still get both ctx = WithValue(ctx, APIVersion, version.Version("x.y")) if id := ctx.RequestID(); id != "123" { t.Fatalf("RequestID() should have been '123', was %q", id) } if ver := ctx.Version(); ver != "x.y" { t.Fatalf("Version() should have been 'x.y', was %q", ver) } }
func TestMiddlewares(t *testing.T) { cfg := &Config{ Version: "0.1omega2", } srv := &Server{ cfg: cfg, } srv.UseMiddleware(middleware.NewVersionMiddleware(version.Version("0.1omega2"), api.DefaultVersion, api.MinVersion)) req, _ := http.NewRequest("GET", "/containers/json", nil) resp := httptest.NewRecorder() ctx := context.Background() localHandler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if httputils.VersionFromContext(ctx) == "" { t.Fatalf("Expected version, got empty string") } if sv := w.Header().Get("Server"); !strings.Contains(sv, "Docker/0.1omega2") { t.Fatalf("Expected server version in the header `Docker/0.1omega2`, got %s", sv) } return nil } handlerFunc := srv.handleWithGlobalMiddlewares(localHandler) if err := handlerFunc(ctx, resp, req, map[string]string{}); err != nil { t.Fatal(err) } }
func makeRawConfigFromV1Config(imageJSON []byte, rootfs *image.RootFS, history []image.History) (map[string]*json.RawMessage, error) { var dver struct { DockerVersion string `json:"docker_version"` } if err := json.Unmarshal(imageJSON, &dver); err != nil { return nil, err } useFallback := versionPkg.Version(dver.DockerVersion).LessThan("1.8.3") if useFallback { var v1Image image.V1Image err := json.Unmarshal(imageJSON, &v1Image) if err != nil { return nil, err } imageJSON, err = json.Marshal(v1Image) if err != nil { return nil, err } } var c map[string]*json.RawMessage if err := json.Unmarshal(imageJSON, &c); err != nil { return nil, err } c["rootfs"] = rawJSON(rootfs) c["history"] = rawJSON(history) return c, nil }
func TestAdjustCPUSharesOldApi(t *testing.T) { apiVersion := version.Version("1.18") hostConfig := &runconfig.HostConfig{ CPUShares: linuxMinCPUShares - 1, } adjustCPUShares(apiVersion, hostConfig) if hostConfig.CPUShares != linuxMinCPUShares { t.Errorf("Expected CPUShares to be %d", linuxMinCPUShares) } hostConfig.CPUShares = linuxMaxCPUShares + 1 adjustCPUShares(apiVersion, hostConfig) if hostConfig.CPUShares != linuxMaxCPUShares { t.Errorf("Expected CPUShares to be %d", linuxMaxCPUShares) } hostConfig.CPUShares = 0 adjustCPUShares(apiVersion, hostConfig) if hostConfig.CPUShares != 0 { t.Error("Expected CPUShares to be unchanged") } hostConfig.CPUShares = 1024 adjustCPUShares(apiVersion, hostConfig) if hostConfig.CPUShares != 1024 { t.Error("Expected CPUShares to be unchanged") } }
func TestAdjustCpuSharesNoAdjustment(t *testing.T) { apiVersion := version.Version("1.19") hostConfig := &runconfig.HostConfig{ CPUShares: linuxMinCpuShares - 1, } adjustCpuShares(apiVersion, hostConfig) if hostConfig.CPUShares != linuxMinCpuShares-1 { t.Errorf("Expected CpuShares to be %d", linuxMinCpuShares-1) } hostConfig.CPUShares = linuxMaxCpuShares + 1 adjustCpuShares(apiVersion, hostConfig) if hostConfig.CPUShares != linuxMaxCpuShares+1 { t.Errorf("Expected CpuShares to be %d", linuxMaxCpuShares+1) } hostConfig.CPUShares = 0 adjustCpuShares(apiVersion, hostConfig) if hostConfig.CPUShares != 0 { t.Error("Expected CpuShares to be unchanged") } hostConfig.CPUShares = 1024 adjustCpuShares(apiVersion, hostConfig) if hostConfig.CPUShares != 1024 { t.Error("Expected CpuShares to be unchanged") } }
func makeHttpHandler(logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, corsHeaders string, dockerVersion version.Version) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // log the request logrus.Debugf("Calling %s %s", localMethod, localRoute) if logging { logrus.Infof("%s %s", r.Method, r.RequestURI) } if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") { userAgent := strings.Split(r.Header.Get("User-Agent"), "/") // v1.20 onwards includes the GOOS of the client after the version // such as Docker/1.7.0 (linux) if len(userAgent) == 2 && strings.Contains(userAgent[1], " ") { userAgent[1] = strings.Split(userAgent[1], " ")[0] } if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) { logrus.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion) } } version := version.Version(mux.Vars(r)["version"]) if version == "" { version = api.Version } if corsHeaders != "" { writeCorsHeaders(w, r, corsHeaders) } if version.GreaterThan(api.Version) { http.Error(w, fmt.Errorf("client is newer than server (client API version: %s, server API version: %s)", version, api.Version).Error(), http.StatusBadRequest) return } if version.LessThan(api.MinVersion) { http.Error(w, fmt.Errorf("client is too old, minimum supported API version is %s, please upgrade your client to a newer version", api.MinVersion).Error(), http.StatusBadRequest) return } w.Header().Set("Server", "Docker/"+dockerversion.VERSION+" ("+runtime.GOOS+")") if err := handlerFunc(version, w, r, mux.Vars(r)); err != nil { logrus.Errorf("Handler for %s %s returned error: %s", localMethod, localRoute, err) httpError(w, err) } } }
func (p *Pod) createNewContainers(daemon *Daemon, jsons []*dockertypes.ContainerJSON) error { var ( ok bool err error ccs dockertypes.ContainerCreateResponse rsp *dockertypes.ContainerJSON r interface{} cleanup = func(id string) { if err != nil { glog.V(1).Infof("rollback container %s of %s", id, p.id) daemon.Daemon.ContainerRm(id, &dockertypes.ContainerRmConfig{}) } } ) for idx, c := range p.spec.Containers { if jsons[idx] != nil { glog.V(1).Infof("do not need to create container %s of pod %s[%d]", c.Name, p.id, idx) continue } config := &container.Config{ Image: c.Image, Cmd: strslice.New(c.Command...), NetworkDisabled: true, } if len(c.Entrypoint) != 0 { config.Entrypoint = strslice.New(c.Entrypoint...) } ccs, err = daemon.Daemon.ContainerCreate(dockertypes.ContainerCreateConfig{ Name: c.Name, Config: config, }) if err != nil { glog.Error(err.Error()) return err } defer cleanup(ccs.ID) glog.Infof("create container %s", ccs.ID) if r, err = daemon.ContainerInspect(ccs.ID, false, version.Version("1.21")); err != nil { return err } if rsp, ok = r.(*dockertypes.ContainerJSON); !ok { err = fmt.Errorf("fail to unpack container json response for %s of %s", c.Name, p.id) return err } jsons[idx] = rsp } return nil }
// Gather engine specs (CPU, memory, constraints, ...). func (e *Engine) updateSpecs() error { info, err := e.client.Info() e.CheckConnectionErr(err) if err != nil { return err } if info.NCPU == 0 || info.MemTotal == 0 { return fmt.Errorf("cannot get resources for this engine, make sure %s is a Docker Engine, not a Swarm manager", e.Addr) } v, err := e.client.Version() e.CheckConnectionErr(err) if err != nil { return err } engineVersion := version.Version(v.Version) // Older versions of Docker don't expose the ID field, Labels and are not supported // by Swarm. Catch the error ASAP and refuse to connect. if engineVersion.LessThan(minSupportedVersion) { err = fmt.Errorf("engine %s is running an unsupported version of Docker Engine. Please upgrade to at least %s", e.Addr, minSupportedVersion) e.CheckConnectionErr(err) return err } e.Lock() defer e.Unlock() // Swarm/docker identifies engine by ID. Updating ID but not updating cluster // index will put the cluster into inconsistent state. If this happens, the // engine should be put to pending state for re-validation. if e.ID == "" { e.ID = info.ID } else if e.ID != info.ID { e.state = statePending message := fmt.Sprintf("Engine (ID: %s, Addr: %s) shows up with another ID:%s. Please remove it from cluster, it can be added back.", e.ID, e.Addr, info.ID) e.lastError = message return fmt.Errorf(message) } e.Name = info.Name e.Cpus = info.NCPU e.Memory = info.MemTotal e.Labels = map[string]string{ "storagedriver": info.Driver, "executiondriver": info.ExecutionDriver, "kernelversion": info.KernelVersion, "operatingsystem": info.OperatingSystem, } for _, label := range info.Labels { kv := strings.SplitN(label, "=", 2) if len(kv) != 2 { message := fmt.Sprintf("Engine (ID: %s, Addr: %s) contains an invalid label (%s) not formatted as \"key=value\".", e.ID, e.Addr, label) return fmt.Errorf(message) } e.Labels[kv[0]] = kv[1] } return nil }
// CmdVersion shows Docker version information. // // Available version information is shown for: client Docker version, client API version, client Go version, client Git commit, client OS/Arch, server Docker version, server API version, server Go version, server Git commit, and server OS/Arch. // // Usage: docker version func (cli *DockerCli) CmdVersion(args ...string) (err error) { cmd := Cli.Subcmd("version", nil, Cli.DockerCommands["version"].Description, true) tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template") cmd.Require(flag.Exact, 0) cmd.ParseFlags(args, true) templateFormat := versionTemplate if *tmplStr != "" { templateFormat = *tmplStr } var tmpl *template.Template if tmpl, err = template.New("").Funcs(funcMap).Parse(templateFormat); err != nil { return Cli.StatusError{StatusCode: 64, Status: "Template parsing error: " + err.Error()} } vd := types.VersionResponse{ Client: &types.Version{ Version: dockerversion.Version, APIVersion: version.Version(cli.client.ClientVersion()), GoVersion: runtime.Version(), GitCommit: dockerversion.GitCommit, BuildTime: dockerversion.BuildTime, Os: runtime.GOOS, Arch: runtime.GOARCH, Experimental: utils.ExperimentalBuild(), }, } serverVersion, err := cli.client.ServerVersion() if err == nil { vd.Server = &serverVersion } // first we need to make BuildTime more human friendly t, errTime := time.Parse(time.RFC3339Nano, vd.Client.BuildTime) if errTime == nil { vd.Client.BuildTime = t.Format(time.ANSIC) } if vd.ServerOK() { t, errTime = time.Parse(time.RFC3339Nano, vd.Server.BuildTime) if errTime == nil { vd.Server.BuildTime = t.Format(time.ANSIC) } } if err2 := tmpl.Execute(cli.out, vd); err2 != nil && err == nil { err = err2 } cli.out.Write([]byte{'\n'}) return err }
// userAgentMiddleware checks the User-Agent header looking for a valid docker client spec. func (s *Server) userAgentMiddleware(handler httputils.APIFunc) httputils.APIFunc { return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") { dockerVersion := version.Version(s.cfg.Version) userAgent := strings.Split(r.Header.Get("User-Agent"), "/") // v1.20 onwards includes the GOOS of the client after the version // such as Docker/1.7.0 (linux) if len(userAgent) == 2 && strings.Contains(userAgent[1], " ") { userAgent[1] = strings.Split(userAgent[1], " ")[0] } if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) { logrus.Warnf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion) } } return handler(ctx, w, r, vars) } }
func TestVersionMiddleware(t *testing.T) { handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if httputils.VersionFromContext(ctx) == "" { t.Fatalf("Expected version, got empty string") } return nil } defaultVersion := version.Version("1.10.0") minVersion := version.Version("1.2.0") m := NewVersionMiddleware(defaultVersion.String(), defaultVersion, minVersion) h := m(handler) req, _ := http.NewRequest("GET", "/containers/json", nil) resp := httptest.NewRecorder() ctx := context.Background() if err := h(ctx, resp, req, map[string]string{}); err != nil { t.Fatal(err) } }
// Version is a utility func to make it easier to get the // API version string associated with this Context/request. func (ctx Context) Version() version.Version { val := ctx.Value(APIVersion) if val == nil { return version.Version("") } ver, ok := val.(version.Version) if !ok { // Ideally we shouldn't panic but we also should never get here panic("Context APIVersion isn't a version.Version") } return ver }
func (c *Container) createByEngine() (*dockertypes.ContainerJSON, error) { var ( ok bool err error ccs dockertypes.ContainerCreateResponse rsp *dockertypes.ContainerJSON r interface{} ) config := &container.Config{ Image: c.spec.Image, Cmd: strslice.New(c.spec.Command...), NetworkDisabled: true, } if len(c.spec.Entrypoint) != 0 { config.Entrypoint = strslice.New(c.spec.Entrypoint...) } if len(c.spec.Envs) != 0 { envs := []string{} for _, env := range c.spec.Envs { envs = append(envs, env.Env+"="+env.Value) } config.Env = envs } ccs, err = c.p.factory.engine.ContainerCreate(dockertypes.ContainerCreateConfig{ Name: c.spec.Name, Config: config, }) if err != nil { return nil, err } c.Log(INFO, "create container %s (w/: %s)", ccs.ID, ccs.Warnings) if r, err = c.p.factory.engine.ContainerInspect(ccs.ID, false, version.Version("1.21")); err != nil { return nil, err } if rsp, ok = r.(*dockertypes.ContainerJSON); !ok { err = fmt.Errorf("fail to unpack container json response for %s of %s", c.spec.Name, c.p.Id()) return nil, err } c.spec.Id = ccs.ID c.updateLogPrefix() return rsp, nil }
// NewVersionMiddleware creates a new Version middleware. func NewVersionMiddleware(versionCheck string, defaultVersion, minVersion version.Version) Middleware { serverVersion := version.Version(versionCheck) return func(handler httputils.APIFunc) httputils.APIFunc { return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { apiVersion := version.Version(vars["version"]) if apiVersion == "" { apiVersion = defaultVersion } if apiVersion.GreaterThan(defaultVersion) { return badRequestError{fmt.Errorf("client is newer than server (client API version: %s, server API version: %s)", apiVersion, defaultVersion)} } if apiVersion.LessThan(minVersion) { return badRequestError{fmt.Errorf("client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version", apiVersion, minVersion)} } header := fmt.Sprintf("Docker/%s (%s)", serverVersion, runtime.GOOS) w.Header().Set("Server", header) ctx = context.WithValue(ctx, httputils.APIVersionKey, apiVersion) return handler(ctx, w, r, vars) } } }
// NewUserAgentMiddleware creates a new UserAgent middleware. func NewUserAgentMiddleware(versionCheck string) Middleware { serverVersion := version.Version(versionCheck) return func(handler httputils.APIFunc) httputils.APIFunc { return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { ctx = context.WithValue(ctx, httputils.UAStringKey, r.Header.Get("User-Agent")) if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") { userAgent := strings.Split(r.Header.Get("User-Agent"), "/") // v1.20 onwards includes the GOOS of the client after the version // such as Docker/1.7.0 (linux) if len(userAgent) == 2 && strings.Contains(userAgent[1], " ") { userAgent[1] = strings.Split(userAgent[1], " ")[0] } if len(userAgent) == 2 && !serverVersion.Equal(version.Version(userAgent[1])) { logrus.Debugf("Client and server don't have the same version (client: %s, server: %s)", userAgent[1], serverVersion) } } return handler(ctx, w, r, vars) } } }
// NewVersionMiddleware creates a new Version middleware. func NewVersionMiddleware(versionCheck string, defaultVersion, minVersion version.Version) Middleware { serverVersion := version.Version(versionCheck) return func(handler httputils.APIFunc) httputils.APIFunc { return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { apiVersion := version.Version(vars["version"]) if apiVersion == "" { apiVersion = defaultVersion } if apiVersion.GreaterThan(defaultVersion) { return errors.ErrorCodeNewerClientVersion.WithArgs(apiVersion, defaultVersion) } if apiVersion.LessThan(minVersion) { return errors.ErrorCodeOldClientVersion.WithArgs(apiVersion, minVersion) } header := fmt.Sprintf("Docker/%s (%s)", serverVersion, runtime.GOOS) w.Header().Set("Server", header) ctx = context.WithValue(ctx, httputils.APIVersionKey, apiVersion) return handler(ctx, w, r, vars) } } }
// MakeImageConfig returns immutable configuration JSON for image based on the // v1Compatibility object, layer digest and parent StrongID. SHA256() of this // config is the new image ID (strongID). func MakeImageConfig(v1Compatibility []byte, layerID, parentID digest.Digest) ([]byte, error) { // Detect images created after 1.8.3 img, err := NewImgJSON(v1Compatibility) if err != nil { return nil, err } useFallback := version.Version(img.DockerVersion).LessThan(noFallbackMinVersion) if useFallback { // Fallback for pre-1.8.3. Calculate base config based on Image struct // so that fields with default values added by Docker will use same ID logrus.Debugf("Using fallback hash for %v", layerID) v1Compatibility, err = json.Marshal(img) if err != nil { return nil, err } } var c map[string]*json.RawMessage if err := json.Unmarshal(v1Compatibility, &c); err != nil { return nil, err } if err := layerID.Validate(); err != nil { return nil, fmt.Errorf("invalid layerID: %v", err) } c["layer_id"] = rawJSON(layerID) if parentID != "" { if err := parentID.Validate(); err != nil { return nil, fmt.Errorf("invalid parentID %v", err) } c["parent_id"] = rawJSON(parentID) } delete(c, "id") delete(c, "parent") delete(c, "Size") // Size is calculated from data on disk and is inconsitent return json.Marshal(c) }
// versionMiddleware checks the api version requirements before passing the request to the server handler. func versionMiddleware(handler httputils.APIFunc) httputils.APIFunc { return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { apiVersion := version.Version(vars["version"]) if apiVersion == "" { apiVersion = api.DefaultVersion } if apiVersion.GreaterThan(api.DefaultVersion) { return errors.ErrorCodeNewerClientVersion.WithArgs(apiVersion, api.DefaultVersion) } if apiVersion.LessThan(api.MinVersion) { return errors.ErrorCodeOldClientVersion.WithArgs(apiVersion, api.DefaultVersion) } w.Header().Set("Server", "Docker/"+dockerversion.Version+" ("+runtime.GOOS+")") ctx = context.WithValue(ctx, httputils.APIVersionKey, apiVersion) return handler(ctx, w, r, vars) } }
func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config) { v := version.Version(cfg.Version) vm := middleware.NewVersionMiddleware(v, api.DefaultVersion, api.MinVersion) s.UseMiddleware(vm) if cfg.EnableCors { c := middleware.NewCORSMiddleware(cfg.CorsHeaders) s.UseMiddleware(c) } u := middleware.NewUserAgentMiddleware(v) s.UseMiddleware(u) if len(cli.Config.AuthorizationPlugins) > 0 { authZPlugins := authorization.NewPlugins(cli.Config.AuthorizationPlugins) handleAuthorization := authorization.NewMiddleware(authZPlugins) s.UseMiddleware(handleAuthorization) } }
func (s *DockerSuite) TestApiStatsNetworkStatsVersioning(c *check.C) { testRequires(c, SameHostDaemon) testRequires(c, DaemonIsLinux) out, _ := runSleepingContainer(c) id := strings.TrimSpace(out) c.Assert(waitRun(id), checker.IsNil) for i := 17; i <= 21; i++ { apiVersion := fmt.Sprintf("v1.%d", i) statsJSONBlob := getVersionedStats(c, id, apiVersion) if version.Version(apiVersion).LessThan("v1.21") { c.Assert(jsonBlobHasLTv121NetworkStats(statsJSONBlob), checker.Equals, true, check.Commentf("Stats JSON blob from API %s %#v does not look like a <v1.21 API stats structure", apiVersion, statsJSONBlob)) } else { c.Assert(jsonBlobHasGTE121NetworkStats(statsJSONBlob), checker.Equals, true, check.Commentf("Stats JSON blob from API %s %#v does not look like a >=v1.21 API stats structure", apiVersion, statsJSONBlob)) } } }
// Gather engine specs (CPU, memory, constraints, ...). func (e *Engine) updateSpecs() error { info, err := e.client.Info() e.CheckConnectionErr(err) if err != nil { return err } if info.NCPU == 0 || info.MemTotal == 0 { return fmt.Errorf("cannot get resources for this engine, make sure %s is a Docker Engine, not a Swarm manager", e.Addr) } v, err := e.client.Version() e.CheckConnectionErr(err) if err != nil { return err } engineVersion := version.Version(v.Version) // Older versions of Docker don't expose the ID field, Labels and are not supported // by Swarm. Catch the error ASAP and refuse to connect. if engineVersion.LessThan(minSupportedVersion) { return fmt.Errorf("engine %s is running an unsupported version of Docker Engine. Please upgrade to at least %s", e.Addr, minSupportedVersion) } e.ID = info.ID e.Name = info.Name e.Cpus = info.NCPU e.Memory = info.MemTotal e.Labels = map[string]string{ "storagedriver": info.Driver, "executiondriver": info.ExecutionDriver, "kernelversion": info.KernelVersion, "operatingsystem": info.OperatingSystem, } for _, label := range info.Labels { kv := strings.SplitN(label, "=", 2) e.Labels[kv[0]] = kv[1] } return nil }
func (p *Pod) TryLoadContainers(daemon *Daemon) ([]*dockertypes.ContainerJSON, error) { var ( containerJsons = make([]*dockertypes.ContainerJSON, len(p.Spec.Containers)) rsp *dockertypes.ContainerJSON ok bool ) if ids, err := daemon.db.GetP2C(p.Id); ids != nil { glog.V(3).Infof("loaded containers for pod %s: %v", p.Id, ids) containerNames := make(map[string]int) for idx, c := range p.Spec.Containers { containerNames[c.Name] = idx } for _, id := range ids { glog.V(3).Infof("Loading container %s of pod %s", id, p.Id) if r, err := daemon.ContainerInspect(id, false, version.Version("1.21")); err == nil { rsp, ok = r.(*dockertypes.ContainerJSON) if !ok { if glog.V(1) { glog.Warningf("fail to load container %s for pod %s", id, p.Id) } continue } n := strings.TrimLeft(rsp.Name, "/") if idx, ok := containerNames[n]; ok { glog.V(1).Infof("Found exist container %s (%s), pod: %s", n, id, p.Id) containerJsons[idx] = rsp } else if glog.V(1) { glog.Warningf("loaded container %s (%s) is not belongs to pod %s", n, id, p.Id) } } } } else { glog.V(3).Infof("no containers for pod %s loaded: %v", p.Id, err) } return containerJsons, nil }
// MakeConfigFromV1Config creates an image config from the legacy V1 config format. func MakeConfigFromV1Config(imageJSON []byte, rootfs *image.RootFS, history []image.History) ([]byte, error) { var dver struct { DockerVersion string `json:"docker_version"` } if err := json.Unmarshal(imageJSON, &dver); err != nil { return nil, err } useFallback := version.Version(dver.DockerVersion).LessThan(noFallbackMinVersion) if useFallback { var v1Image image.V1Image err := json.Unmarshal(imageJSON, &v1Image) if err != nil { return nil, err } imageJSON, err = json.Marshal(v1Image) if err != nil { return nil, err } } var c map[string]*json.RawMessage if err := json.Unmarshal(imageJSON, &c); err != nil { return nil, err } delete(c, "id") delete(c, "parent") delete(c, "Size") // Size is calculated from data on disk and is inconsistent delete(c, "parent_id") delete(c, "layer_id") delete(c, "throwaway") c["rootfs"] = rawJSON(rootfs) c["history"] = rawJSON(history) return json.Marshal(c) }
func createMonitorRouter(s *MonitorServer) *mux.Router { r := mux.NewRouter() m := map[string]map[string]HttpMonApiFunc{ "GET": { "/containers/{name:.*}/_ping": s.ping, "/containers/{name:.*}/state": s.containerState, "/containers/{name:.*}/watch": s.containerWatch, }, "POST": { "/containers/{name:.*}/start": s.postContainersStart, "/containers/{name:.*}/resize": s.postContainersResize, "/containers/{name:.*}/attach": s.postContainersAttach, "/containers/{name:.*}/stop": s.postContainersStop, }, } enableCors := s.cfg.EnableCors for method, routes := range m { for route, fct := range routes { log.Infof("Registering %s, %s", method, route) // NOTE: scope issue, make sure the variables are local and won't be changed localRoute := route localFct := fct localMethod := method // build the handler function f := makeHttpMonHandler(true, localMethod, localRoute, localFct, enableCors, version.Version(dockerversion.VERSION)) // add the new route if localRoute == "" { r.Methods(localMethod).HandlerFunc(f) } else { r.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(f) r.Path(localRoute).Methods(localMethod).HandlerFunc(f) } } } return r }
func (c *Container) loadJson() *dockertypes.ContainerJSON { c.Log(TRACE, "Loading container") if r, err := c.p.factory.engine.ContainerInspect(c.spec.Id, false, version.Version("1.21")); err == nil { rsp, ok := r.(*dockertypes.ContainerJSON) if !ok { c.Log(ERROR, "fail to got loaded container info: %v", r) return nil } n := strings.TrimLeft(rsp.Name, "/") if c.spec.Name != rsp.Name { c.Log(ERROR, "name mismatch of loaded container, loaded is %s", n) c.spec.Id = "" return nil } c.Log(DEBUG, "Found exist container") return rsp } else { c.Log(ERROR, "fail to load container: %v", err) return nil } }
"github.com/docker/docker/pkg/version" "github.com/samalba/dockerclient" "github.com/samalba/dockerclient/nopclient" ) const ( // Force-refresh the state of the engine this often. stateRefreshMinRange = 30 * time.Second stateRefreshMaxRange = 60 * time.Second stateRefreshRetries = 3 // Timeout for requests sent out to the engine. requestTimeout = 10 * time.Second // Minimum docker engine version supported by swarm. minSupportedVersion = version.Version("1.6.0") ) // delayer offers a simple API to random delay within a given time range. type delayer struct { rangeMin time.Duration rangeMax time.Duration r *rand.Rand l sync.Mutex } func newDelayer(rangeMin, rangeMax time.Duration) *delayer { return &delayer{ rangeMin: rangeMin, rangeMax: rangeMax,