Пример #1
0
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)
	}
}
Пример #2
0
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)
		}
	}
}
Пример #3
0
// 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")
	}
}
Пример #4
0
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)
	}
}
Пример #6
0
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)
	}
}
Пример #7
0
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")
	}
}
Пример #9
0
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")
	}
}
Пример #10
0
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)
		}
	}
}
Пример #11
0
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
}
Пример #12
0
// 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
}
Пример #13
0
// 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
}
Пример #14
0
// 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)
	}
}
Пример #15
0
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)
	}
}
Пример #16
0
// 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
}
Пример #17
0
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
}
Пример #18
0
// 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)
		}
	}
}
Пример #19
0
// 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)
		}
	}
}
Пример #20
0
// 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)
		}
	}
}
Пример #21
0
// 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)
}
Пример #22
0
// 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)
	}
}
Пример #23
0
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)
	}
}
Пример #24
0
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))
		}
	}
}
Пример #25
0
// 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
}
Пример #26
0
Файл: pod.go Проект: juito/hyper
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
}
Пример #27
0
// 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)
}
Пример #28
0
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
}
Пример #29
0
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
	}
}
Пример #30
0
	"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,