浏览代码

Merge pull request #46898 from thaJeztah/backend_types

api/types: move ContainerCreateConfig, ContainerRmConfig to api/types/backend
Sebastiaan van Stijn 1 年之前
父节点
当前提交
4fa5a79833

+ 2 - 2
api/server/router/container/backend.go

@@ -32,13 +32,13 @@ type copyBackend interface {
 
 // stateBackend includes functions to implement to provide container state lifecycle functionality.
 type stateBackend interface {
-	ContainerCreate(ctx context.Context, config types.ContainerCreateConfig) (container.CreateResponse, error)
+	ContainerCreate(ctx context.Context, config backend.ContainerCreateConfig) (container.CreateResponse, error)
 	ContainerKill(name string, signal string) error
 	ContainerPause(name string) error
 	ContainerRename(oldName, newName string) error
 	ContainerResize(name string, height, width int) error
 	ContainerRestart(ctx context.Context, name string, options container.StopOptions) error
-	ContainerRm(name string, config *types.ContainerRmConfig) error
+	ContainerRm(name string, config *backend.ContainerRmConfig) error
 	ContainerStart(ctx context.Context, name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
 	ContainerStop(ctx context.Context, name string, options container.StopOptions) error
 	ContainerUnpause(name string) error

+ 2 - 2
api/server/router/container/container_routes.go

@@ -643,7 +643,7 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
 		hostConfig.PidsLimit = nil
 	}
 
-	ccr, err := s.backend.ContainerCreate(ctx, types.ContainerCreateConfig{
+	ccr, err := s.backend.ContainerCreate(ctx, backend.ContainerCreateConfig{
 		Name:             name,
 		Config:           config,
 		HostConfig:       hostConfig,
@@ -712,7 +712,7 @@ func (s *containerRouter) deleteContainers(ctx context.Context, w http.ResponseW
 	}
 
 	name := vars["name"]
-	config := &types.ContainerRmConfig{
+	config := &backend.ContainerRmConfig{
 		ForceRemove:  httputils.BoolValue(r, "force"),
 		RemoveVolume: httputils.BoolValue(r, "v"),
 		RemoveLink:   httputils.BoolValue(r, "link"),

+ 19 - 0
api/types/backend/backend.go

@@ -7,8 +7,27 @@ import (
 
 	"github.com/distribution/reference"
 	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/api/types/network"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
+// ContainerCreateConfig is the parameter set to ContainerCreate()
+type ContainerCreateConfig struct {
+	Name             string
+	Config           *container.Config
+	HostConfig       *container.HostConfig
+	NetworkingConfig *network.NetworkingConfig
+	Platform         *ocispec.Platform
+	AdjustCPUShares  bool
+}
+
+// ContainerRmConfig holds arguments for the container remove
+// operation. This struct is used to tell the backend what operations
+// to perform.
+type ContainerRmConfig struct {
+	ForceRemove, RemoveVolume, RemoveLink bool
+}
+
 // ContainerAttachConfig holds the streams to use when connecting to a container to view logs.
 type ContainerAttachConfig struct {
 	GetStreams func(multiplexed bool) (io.ReadCloser, io.Writer, io.Writer, error)

+ 0 - 23
api/types/configs.go

@@ -1,32 +1,9 @@
 package types // import "github.com/docker/docker/api/types"
 
-import (
-	"github.com/docker/docker/api/types/container"
-	"github.com/docker/docker/api/types/network"
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
-)
-
 // configs holds structs used for internal communication between the
 // frontend (such as an http server) and the backend (such as the
 // docker daemon).
 
-// ContainerCreateConfig is the parameter set to ContainerCreate()
-type ContainerCreateConfig struct {
-	Name             string
-	Config           *container.Config
-	HostConfig       *container.HostConfig
-	NetworkingConfig *network.NetworkingConfig
-	Platform         *ocispec.Platform
-	AdjustCPUShares  bool
-}
-
-// ContainerRmConfig holds arguments for the container remove
-// operation. This struct is used to tell the backend what operations
-// to perform.
-type ContainerRmConfig struct {
-	ForceRemove, RemoveVolume, RemoveLink bool
-}
-
 // ExecConfig is a small subset of the Config struct that holds the configuration
 // for the exec feature of docker.
 type ExecConfig struct {

+ 2 - 3
builder/builder.go

@@ -8,7 +8,6 @@ import (
 	"context"
 	"io"
 
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/api/types/container"
 	containerpkg "github.com/docker/docker/container"
@@ -60,9 +59,9 @@ type ExecBackend interface {
 	// ContainerAttachRaw attaches to container.
 	ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout, stderr io.Writer, stream bool, attached chan struct{}) error
 	// ContainerCreateIgnoreImagesArgsEscaped creates a new Docker container and returns potential warnings
-	ContainerCreateIgnoreImagesArgsEscaped(ctx context.Context, config types.ContainerCreateConfig) (container.CreateResponse, error)
+	ContainerCreateIgnoreImagesArgsEscaped(ctx context.Context, config backend.ContainerCreateConfig) (container.CreateResponse, error)
 	// ContainerRm removes a container specified by `id`.
-	ContainerRm(name string, config *types.ContainerRmConfig) error
+	ContainerRm(name string, config *backend.ContainerRmConfig) error
 	// ContainerKill stops the container execution abruptly.
 	ContainerKill(containerID string, sig string) error
 	// ContainerStart starts a new container

+ 6 - 6
builder/dockerfile/containerbackend.go

@@ -6,7 +6,7 @@ import (
 	"io"
 
 	"github.com/containerd/log"
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/builder"
 	containerpkg "github.com/docker/docker/container"
@@ -29,15 +29,15 @@ func newContainerManager(docker builder.ExecBackend) *containerManager {
 
 // Create a container
 func (c *containerManager) Create(ctx context.Context, runConfig *container.Config, hostConfig *container.HostConfig) (container.CreateResponse, error) {
-	container, err := c.backend.ContainerCreateIgnoreImagesArgsEscaped(ctx, types.ContainerCreateConfig{
+	ctr, err := c.backend.ContainerCreateIgnoreImagesArgsEscaped(ctx, backend.ContainerCreateConfig{
 		Config:     runConfig,
 		HostConfig: hostConfig,
 	})
 	if err != nil {
-		return container, err
+		return ctr, err
 	}
-	c.tmpContainers[container.ID] = struct{}{}
-	return container, nil
+	c.tmpContainers[ctr.ID] = struct{}{}
+	return ctr, nil
 }
 
 var errCancelled = errors.New("build cancelled")
@@ -123,7 +123,7 @@ func (e *statusCodeError) StatusCode() int {
 }
 
 func (c *containerManager) removeContainer(containerID string, stdout io.Writer) error {
-	rmConfig := &types.ContainerRmConfig{
+	rmConfig := &backend.ContainerRmConfig{
 		ForceRemove:  true,
 		RemoveVolume: true,
 	}

+ 3 - 3
builder/dockerfile/dispatchers_test.go

@@ -479,7 +479,7 @@ func TestRunWithBuildArgs(t *testing.T) {
 			config: &container.Config{Cmd: origCmd},
 		}, nil, nil
 	}
-	mockBackend.containerCreateFunc = func(config types.ContainerCreateConfig) (container.CreateResponse, error) {
+	mockBackend.containerCreateFunc = func(config backend.ContainerCreateConfig) (container.CreateResponse, error) {
 		// Check the runConfig.Cmd sent to create()
 		assert.Check(t, is.DeepEqual(cmdWithShell, config.Config.Cmd))
 		assert.Check(t, is.Contains(config.Config.Env, "one=two"))
@@ -548,7 +548,7 @@ func TestRunIgnoresHealthcheck(t *testing.T) {
 			config: &container.Config{Cmd: origCmd},
 		}, nil, nil
 	}
-	mockBackend.containerCreateFunc = func(config types.ContainerCreateConfig) (container.CreateResponse, error) {
+	mockBackend.containerCreateFunc = func(config backend.ContainerCreateConfig) (container.CreateResponse, error) {
 		return container.CreateResponse{ID: "12345"}, nil
 	}
 	mockBackend.commitFunc = func(cfg backend.CommitConfig) (image.ID, error) {
@@ -575,7 +575,7 @@ func TestRunIgnoresHealthcheck(t *testing.T) {
 	assert.NilError(t, dispatch(context.TODO(), sb, cmd))
 	assert.Assert(t, sb.state.runConfig.Healthcheck != nil)
 
-	mockBackend.containerCreateFunc = func(config types.ContainerCreateConfig) (container.CreateResponse, error) {
+	mockBackend.containerCreateFunc = func(config backend.ContainerCreateConfig) (container.CreateResponse, error) {
 		// Check the Healthcheck is disabled.
 		assert.Check(t, is.DeepEqual([]string{"NONE"}, config.Config.Healthcheck.Test))
 		return container.CreateResponse{ID: "123456"}, nil

+ 3 - 4
builder/dockerfile/mockbackend_test.go

@@ -6,7 +6,6 @@ import (
 	"io"
 	"runtime"
 
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/builder"
@@ -18,7 +17,7 @@ import (
 
 // MockBackend implements the builder.Backend interface for unit testing
 type MockBackend struct {
-	containerCreateFunc func(config types.ContainerCreateConfig) (container.CreateResponse, error)
+	containerCreateFunc func(config backend.ContainerCreateConfig) (container.CreateResponse, error)
 	commitFunc          func(backend.CommitConfig) (image.ID, error)
 	getImageFunc        func(string) (builder.Image, builder.ROLayer, error)
 	makeImageCacheFunc  func(cacheFrom []string) builder.ImageCache
@@ -28,14 +27,14 @@ func (m *MockBackend) ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout
 	return nil
 }
 
-func (m *MockBackend) ContainerCreateIgnoreImagesArgsEscaped(ctx context.Context, config types.ContainerCreateConfig) (container.CreateResponse, error) {
+func (m *MockBackend) ContainerCreateIgnoreImagesArgsEscaped(ctx context.Context, config backend.ContainerCreateConfig) (container.CreateResponse, error) {
 	if m.containerCreateFunc != nil {
 		return m.containerCreateFunc(config)
 	}
 	return container.CreateResponse{}, nil
 }
 
-func (m *MockBackend) ContainerRm(name string, config *types.ContainerRmConfig) error {
+func (m *MockBackend) ContainerRm(name string, config *backend.ContainerRmConfig) error {
 	return nil
 }
 

+ 2 - 2
daemon/cluster/executor/backend.go

@@ -38,7 +38,7 @@ type Backend interface {
 	FindNetwork(idName string) (*libnetwork.Network, error)
 	SetupIngress(clustertypes.NetworkCreateRequest, string) (<-chan struct{}, error)
 	ReleaseIngress() (<-chan struct{}, error)
-	CreateManagedContainer(ctx context.Context, config types.ContainerCreateConfig) (container.CreateResponse, error)
+	CreateManagedContainer(ctx context.Context, config backend.ContainerCreateConfig) (container.CreateResponse, error)
 	ContainerStart(ctx context.Context, name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
 	ContainerStop(ctx context.Context, name string, config container.StopOptions) error
 	ContainerLogs(ctx context.Context, name string, config *container.LogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
@@ -48,7 +48,7 @@ type Backend interface {
 	UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error
 	ContainerInspectCurrent(ctx context.Context, name string, size bool) (*types.ContainerJSON, error)
 	ContainerWait(ctx context.Context, name string, condition containerpkg.WaitCondition) (<-chan containerpkg.StateStatus, error)
-	ContainerRm(name string, config *types.ContainerRmConfig) error
+	ContainerRm(name string, config *backend.ContainerRmConfig) error
 	ContainerKill(name string, sig string) error
 	SetContainerDependencyStore(name string, store exec.DependencyGetter) error
 	SetContainerSecretReferences(name string, refs []*swarm.SecretReference) error

+ 2 - 2
daemon/cluster/executor/container/adapter.go

@@ -293,7 +293,7 @@ func (c *containerAdapter) waitForDetach(ctx context.Context) error {
 func (c *containerAdapter) create(ctx context.Context) error {
 	var cr containertypes.CreateResponse
 	var err error
-	if cr, err = c.backend.CreateManagedContainer(ctx, types.ContainerCreateConfig{
+	if cr, err = c.backend.CreateManagedContainer(ctx, backend.ContainerCreateConfig{
 		Name:       c.container.name(),
 		Config:     c.container.config(),
 		HostConfig: c.container.hostConfig(c.dependencies.Volumes()),
@@ -417,7 +417,7 @@ func (c *containerAdapter) terminate(ctx context.Context) error {
 }
 
 func (c *containerAdapter) remove(ctx context.Context) error {
-	return c.backend.ContainerRm(c.container.name(), &types.ContainerRmConfig{
+	return c.backend.ContainerRm(c.container.name(), &backend.ContainerRmConfig{
 		RemoveVolume: true,
 		ForceRemove:  true,
 	})

+ 2 - 2
daemon/cluster/swarm.go

@@ -8,7 +8,7 @@ import (
 	"time"
 
 	"github.com/containerd/log"
-	apitypes "github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/filters"
 	types "github.com/docker/docker/api/types/swarm"
@@ -414,7 +414,7 @@ func (c *Cluster) Leave(ctx context.Context, force bool) error {
 			return err
 		}
 		for _, id := range nodeContainers {
-			if err := c.config.Backend.ContainerRm(id, &apitypes.ContainerRmConfig{ForceRemove: true}); err != nil {
+			if err := c.config.Backend.ContainerRm(id, &backend.ContainerRmConfig{ForceRemove: true}); err != nil {
 				log.G(ctx).Errorf("error removing %v: %v", id, err)
 			}
 		}

+ 6 - 6
daemon/create.go

@@ -9,7 +9,7 @@ import (
 
 	"github.com/containerd/containerd/platforms"
 	"github.com/containerd/log"
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/backend"
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/events"
 	imagetypes "github.com/docker/docker/api/types/image"
@@ -28,13 +28,13 @@ import (
 )
 
 type createOpts struct {
-	params                  types.ContainerCreateConfig
+	params                  backend.ContainerCreateConfig
 	managed                 bool
 	ignoreImagesArgsEscaped bool
 }
 
 // CreateManagedContainer creates a container that is managed by a Service
-func (daemon *Daemon) CreateManagedContainer(ctx context.Context, params types.ContainerCreateConfig) (containertypes.CreateResponse, error) {
+func (daemon *Daemon) CreateManagedContainer(ctx context.Context, params backend.ContainerCreateConfig) (containertypes.CreateResponse, error) {
 	return daemon.containerCreate(ctx, daemon.config(), createOpts{
 		params:  params,
 		managed: true,
@@ -42,7 +42,7 @@ func (daemon *Daemon) CreateManagedContainer(ctx context.Context, params types.C
 }
 
 // ContainerCreate creates a regular container
-func (daemon *Daemon) ContainerCreate(ctx context.Context, params types.ContainerCreateConfig) (containertypes.CreateResponse, error) {
+func (daemon *Daemon) ContainerCreate(ctx context.Context, params backend.ContainerCreateConfig) (containertypes.CreateResponse, error) {
 	return daemon.containerCreate(ctx, daemon.config(), createOpts{
 		params: params,
 	})
@@ -50,7 +50,7 @@ func (daemon *Daemon) ContainerCreate(ctx context.Context, params types.Containe
 
 // ContainerCreateIgnoreImagesArgsEscaped creates a regular container. This is called from the builder RUN case
 // and ensures that we do not take the images ArgsEscaped
-func (daemon *Daemon) ContainerCreateIgnoreImagesArgsEscaped(ctx context.Context, params types.ContainerCreateConfig) (containertypes.CreateResponse, error) {
+func (daemon *Daemon) ContainerCreateIgnoreImagesArgsEscaped(ctx context.Context, params backend.ContainerCreateConfig) (containertypes.CreateResponse, error) {
 	return daemon.containerCreate(ctx, daemon.config(), createOpts{
 		params:                  params,
 		ignoreImagesArgsEscaped: true,
@@ -176,7 +176,7 @@ func (daemon *Daemon) create(ctx context.Context, daemonCfg *config.Config, opts
 	}
 	defer func() {
 		if retErr != nil {
-			err = daemon.cleanupContainer(ctr, types.ContainerRmConfig{
+			err = daemon.cleanupContainer(ctr, backend.ContainerRmConfig{
 				ForceRemove:  true,
 				RemoveVolume: true,
 			})

+ 2 - 1
daemon/daemon.go

@@ -26,6 +26,7 @@ import (
 	"github.com/distribution/reference"
 	dist "github.com/docker/distribution"
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/backend"
 	containertypes "github.com/docker/docker/api/types/container"
 	imagetypes "github.com/docker/docker/api/types/image"
 	registrytypes "github.com/docker/docker/api/types/registry"
@@ -594,7 +595,7 @@ func (daemon *Daemon) restore(cfg *configStore) error {
 		go func(cid string) {
 			_ = sem.Acquire(context.Background(), 1)
 
-			if err := daemon.containerRm(&cfg.Config, cid, &types.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err != nil {
+			if err := daemon.containerRm(&cfg.Config, cid, &backend.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err != nil {
 				log.G(context.TODO()).WithField("container", cid).WithError(err).Error("failed to remove container")
 			}
 

+ 4 - 4
daemon/delete.go

@@ -11,7 +11,7 @@ import (
 	cerrdefs "github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/leases"
 	"github.com/containerd/log"
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/backend"
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/events"
 	"github.com/docker/docker/container"
@@ -26,11 +26,11 @@ import (
 // is returned if the container is not found, or if the remove
 // fails. If the remove succeeds, the container name is released, and
 // network links are removed.
-func (daemon *Daemon) ContainerRm(name string, config *types.ContainerRmConfig) error {
+func (daemon *Daemon) ContainerRm(name string, config *backend.ContainerRmConfig) error {
 	return daemon.containerRm(&daemon.config().Config, name, config)
 }
 
-func (daemon *Daemon) containerRm(cfg *config.Config, name string, opts *types.ContainerRmConfig) error {
+func (daemon *Daemon) containerRm(cfg *config.Config, name string, opts *backend.ContainerRmConfig) error {
 	start := time.Now()
 	ctr, err := daemon.GetContainer(name)
 	if err != nil {
@@ -87,7 +87,7 @@ func (daemon *Daemon) rmLink(cfg *config.Config, container *container.Container,
 
 // cleanupContainer unregisters a container from the daemon, stops stats
 // collection and cleanly removes contents and metadata from the filesystem.
-func (daemon *Daemon) cleanupContainer(container *container.Container, config types.ContainerRmConfig) error {
+func (daemon *Daemon) cleanupContainer(container *container.Container, config backend.ContainerRmConfig) error {
 	if container.IsRunning() {
 		if !config.ForceRemove {
 			if state := container.StateString(); state == "paused" {

+ 3 - 3
daemon/delete_test.go

@@ -5,7 +5,7 @@ import (
 	"os"
 	"testing"
 
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/backend"
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/errdefs"
@@ -74,7 +74,7 @@ func TestContainerDelete(t *testing.T) {
 			defer cleanup()
 			d.containers.Add(c.ID, c)
 
-			err := d.ContainerRm(c.ID, &types.ContainerRmConfig{ForceRemove: false})
+			err := d.ContainerRm(c.ID, &backend.ContainerRmConfig{ForceRemove: false})
 			assert.Check(t, is.ErrorType(err, errdefs.IsConflict))
 			assert.Check(t, is.ErrorContains(err, tc.errMsg))
 		})
@@ -93,6 +93,6 @@ func TestContainerDoubleDelete(t *testing.T) {
 
 	// Try to remove the container when its state is removalInProgress.
 	// It should return an error indicating it is under removal progress.
-	err := d.ContainerRm(c.ID, &types.ContainerRmConfig{ForceRemove: true})
+	err := d.ContainerRm(c.ID, &backend.ContainerRmConfig{ForceRemove: true})
 	assert.Check(t, is.ErrorContains(err, fmt.Sprintf("removal of container %s is already in progress", c.ID)))
 }

+ 2 - 2
daemon/monitor.go

@@ -6,7 +6,7 @@ import (
 	"time"
 
 	"github.com/containerd/log"
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/api/types/events"
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/config"
@@ -306,7 +306,7 @@ func (daemon *Daemon) autoRemove(cfg *config.Config, c *container.Container) {
 		return
 	}
 
-	err := daemon.containerRm(cfg, c.ID, &types.ContainerRmConfig{ForceRemove: true, RemoveVolume: true})
+	err := daemon.containerRm(cfg, c.ID, &backend.ContainerRmConfig{ForceRemove: true, RemoveVolume: true})
 	if err == nil {
 		return
 	}

+ 2 - 1
daemon/prune.go

@@ -9,6 +9,7 @@ import (
 
 	"github.com/containerd/log"
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/api/types/events"
 	"github.com/docker/docker/api/types/filters"
 	timetypes "github.com/docker/docker/api/types/time"
@@ -78,7 +79,7 @@ func (daemon *Daemon) ContainersPrune(ctx context.Context, pruneFilters filters.
 				return nil, err
 			}
 			// TODO: sets RmLink to true?
-			err = daemon.containerRm(cfg, c.ID, &types.ContainerRmConfig{})
+			err = daemon.containerRm(cfg, c.ID, &backend.ContainerRmConfig{})
 			if err != nil {
 				log.G(ctx).Warnf("failed to prune container %s: %v", c.ID, err)
 				continue

+ 2 - 2
daemon/start.go

@@ -6,7 +6,7 @@ import (
 	"time"
 
 	"github.com/containerd/log"
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/backend"
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/events"
 	"github.com/docker/docker/container"
@@ -142,7 +142,7 @@ func (daemon *Daemon) containerStart(ctx context.Context, daemonCfg *configStore
 			// if containers AutoRemove flag is set, remove it after clean up
 			if container.HostConfig.AutoRemove {
 				container.Unlock()
-				if err := daemon.containerRm(&daemonCfg.Config, container.ID, &types.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err != nil {
+				if err := daemon.containerRm(&daemonCfg.Config, container.ID, &backend.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err != nil {
 					log.G(ctx).Errorf("can't remove container %s: %v", container.ID, err)
 				}
 				container.Lock()