Open Kilda Java Documentation
proc.py
Go to the documentation of this file.
1 # Copyright 2017 Telstra Open Source
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 
16 import errno
17 import fcntl
18 import os
19 import time
20 
21 from kilda.traffexam import common
22 from kilda.traffexam import exc
23 
24 
26  def __init__(self, path):
27  self.path = path
28 
29  def update(self):
30  with self._open() as pid_file:
31  self._ensure_owning(pid_file)
32  self._write(pid_file)
33 
34  def acquire(self):
35  with self._open() as pid_file:
36  pid = self._read(pid_file)
37  if pid is not None and self.ping_proc(pid):
38  raise exc.PidFileBusyError(self.path, pid)
39  self._write(pid_file)
40 
41  def release(self):
42  with self._open() as pid_file:
43  self._ensure_owning(pid_file)
44  try:
45  os.unlink(self.path)
46  except OSError as e:
47  raise exc.PidFileError(self.path) from e
48 
49  def ping_proc(self, pid):
50  try:
51  os.kill(pid, 0)
52  return True
53  except OSError as e:
54  if e.errno != errno.ESRCH:
55  raise exc.PidFileError(self.path) from e
56 
57  return False
58 
59  def _open(self):
60  for attempt in range(5):
61  pid_fd = None
62  try:
63  pid_fd = os.open(self.path, os.O_RDWR | os.O_CREAT)
64  fcntl.flock(pid_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
65  except OSError as e:
66  if pid_fd is not None:
67  os.close(pid_fd)
68  if e.errno != errno.EWOULDBLOCK:
69  raise exc.PidFileError(self.path) from e
70 
71  time.sleep(0.1)
72  continue
73 
74  break
75  else:
76  raise exc.PidFileLockError(self.path)
77 
78  return os.fdopen(pid_fd, 'w+t')
79 
80  def _read(self, pid_file):
81  pid = None
82  try:
83  raw = pid_file.read(1024)
84  if raw:
85  pid = int(raw, 10)
86  except (IOError, ValueError) as e:
87  raise exc.PidFileError(self.path) from e
88  return pid
89 
90  def _write(self, pid_file):
91  try:
92  pid_file.seek(0)
93  pid_file.write('{}\n'.format(os.getpid()))
94  pid_file.close()
95  except IOError as e:
96  raise exc.PidFileError(self.path) from e
97 
98  def _ensure_owning(self, pid_file):
99  pid = self._read(pid_file)
100  if pid != os.getpid():
101  raise exc.PidFileStolenError(self.path, pid)
def _write(self, pid_file)
Definition: proc.py:90
def ping_proc(self, pid)
Definition: proc.py:49
def _ensure_owning(self, pid_file)
Definition: proc.py:98
def __init__(self, path)
Definition: proc.py:26
def _read(self, pid_file)
Definition: proc.py:80