diff --git a/cmd/kubelet/app/options/options.go b/cmd/kubelet/app/options/options.go index 00ea40aed94..af60672f583 100644 --- a/cmd/kubelet/app/options/options.go +++ b/cmd/kubelet/app/options/options.go @@ -105,6 +105,7 @@ func NewKubeletServer() *KubeletServer { NodeStatusUpdateFrequency: unversioned.Duration{10 * time.Second}, NodeLabels: make(map[string]string), OOMScoreAdj: qos.KubeletOOMScoreAdj, + LockFilePath: "/var/run/lock/kubelet.lock", PodInfraContainerImage: kubetypes.PodInfraContainerImage, Port: ports.KubeletPort, ReadOnlyPort: ports.KubeletReadOnlyPort, @@ -194,6 +195,7 @@ func (s *KubeletServer) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&s.ResourceContainer, "resource-container", s.ResourceContainer, "Absolute name of the resource-only container to create and run the Kubelet in (Default: /kubelet).") fs.StringVar(&s.CgroupRoot, "cgroup-root", s.CgroupRoot, "Optional root cgroup to use for pods. This is handled by the container runtime on a best effort basis. Default: '', which means use the container runtime default.") fs.StringVar(&s.ContainerRuntime, "container-runtime", s.ContainerRuntime, "The container runtime to use. Possible values: 'docker', 'rkt'. Default: 'docker'.") + fs.StringVar(&s.LockFilePath, "lock-file", s.LockFilePath, " The path to file for kubelet to use as a lock file.") fs.StringVar(&s.RktPath, "rkt-path", s.RktPath, "Path of rkt binary. Leave empty to use the first rkt in $PATH. Only used if --container-runtime='rkt'") fs.StringVar(&s.RktStage1Image, "rkt-stage1-image", s.RktStage1Image, "image to use as stage1. Local paths and http/https URLs are supported. If empty, the 'stage1.aci' in the same directory as '--rkt-path' will be used") fs.StringVar(&s.SystemContainer, "system-container", s.SystemContainer, "Optional resource-only container in which to place all non-kernel processes that are not already in a container. Empty for no container. Rolling back the flag requires a reboot. (Default: \"\").") diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go index a621751f922..56594c3c87e 100644 --- a/cmd/kubelet/app/server.go +++ b/cmd/kubelet/app/server.go @@ -58,6 +58,7 @@ import ( "k8s.io/kubernetes/pkg/kubelet/server" kubetypes "k8s.io/kubernetes/pkg/kubelet/types" "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/flock" "k8s.io/kubernetes/pkg/util/io" "k8s.io/kubernetes/pkg/util/mount" nodeutil "k8s.io/kubernetes/pkg/util/node" @@ -262,6 +263,12 @@ func UnsecuredKubeletConfig(s *options.KubeletServer) (*KubeletConfig, error) { // will be ignored. func Run(s *options.KubeletServer, kcfg *KubeletConfig) error { var err error + if s.LockFilePath != "" { + glog.Infof("aquiring lock on %q", s.LockFilePath) + if err := flock.Acquire(s.LockFilePath); err != nil { + return fmt.Errorf("unable to aquire file lock on %q: %v", s.LockFilePath, err) + } + } if kcfg == nil { cfg, err := UnsecuredKubeletConfig(s) if err != nil { diff --git a/hack/verify-flags/known-flags.txt b/hack/verify-flags/known-flags.txt index 5555264cf54..b3917feacf3 100644 --- a/hack/verify-flags/known-flags.txt +++ b/hack/verify-flags/known-flags.txt @@ -383,3 +383,4 @@ leader-elect-renew-deadline leader-elect-retry-period watch-cache-sizes configure-hairpin-mode +lock-file diff --git a/pkg/apis/componentconfig/types.go b/pkg/apis/componentconfig/types.go index 0a3f0451410..3127071c557 100644 --- a/pkg/apis/componentconfig/types.go +++ b/pkg/apis/componentconfig/types.go @@ -234,6 +234,10 @@ type KubeletConfiguration struct { // rktPath is hte path of rkt binary. Leave empty to use the first rkt in // $PATH. RktPath string `json:"rktPath,omitempty"` + // lockFilePath is the path that kubelet will use to as a lock file. + // It uses this file as a lock to synchronize with other kubelet processes + // that may be running. + LockFilePath string `json:"lockFilePath"` // rktStage1Image is the image to use as stage1. Local paths and // http/https URLs are supported. RktStage1Image string `json:"rktStage1Image,omitempty"` diff --git a/pkg/util/flock/flock_other.go b/pkg/util/flock/flock_other.go new file mode 100644 index 00000000000..b80981882d8 --- /dev/null +++ b/pkg/util/flock/flock_other.go @@ -0,0 +1,24 @@ +// +build !linux,!darwin,!freebsd,!openbsd,!netbsd,!dragonfly + +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flock + +// Acquire is not implemented on non-unix systems. +func Acquire(path string) error { + return nil +} diff --git a/pkg/util/flock/flock_unix.go b/pkg/util/flock/flock_unix.go new file mode 100644 index 00000000000..88ca8d700fc --- /dev/null +++ b/pkg/util/flock/flock_unix.go @@ -0,0 +1,51 @@ +// +build linux darwin freebsd openbsd netbsd dragonfly + +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flock + +import ( + "os" + "sync" + + "golang.org/x/sys/unix" +) + +var ( + // lock guards lockfile. Assignment is not atomic. + lock sync.Mutex + // os.File has a runtime.Finalizer so the fd will be closed if the struct + // is garbage collected. Let's hold onto a reference so that doesn't happen. + lockfile *os.File +) + +// Acquire acquires a lock on a file for the duration of the process. This method +// is reentrant. +func Acquire(path string) error { + lock.Lock() + defer lock.Unlock() + var err error + if lockfile, err = os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600); err != nil { + return err + } + + opts := unix.Flock_t{Type: unix.F_WRLCK} + if err := unix.FcntlFlock(lockfile.Fd(), unix.F_SETLKW, &opts); err != nil { + return err + } + return nil +}