prevent running second copy of fuelmenu
Create a file and take a lock on it before running main part of fuel-menu, so running two copies would be impossible. This patch adds an option -l, --lock-file to have ability to specify path to lock file. Change-Id: I8ab41e6e068caa0881e0affcbfb5695a9025b762 Closes-Bug: #1566401
This commit is contained in:
parent
cc4628c865
commit
3f84153673
|
@ -11,11 +11,14 @@
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
from __future__ import print_function
|
||||||
|
import fcntl
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import random as _random
|
import random as _random
|
||||||
import string
|
import string
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
from fuelmenu import consts
|
from fuelmenu import consts
|
||||||
|
|
||||||
|
@ -86,3 +89,21 @@ def gensalt():
|
||||||
sha512prefix = "$6$"
|
sha512prefix = "$6$"
|
||||||
random_letters = ''.join(random.choice(letters) for _ in range(16))
|
random_letters = ''.join(random.choice(letters) for _ in range(16))
|
||||||
return sha512prefix + random_letters
|
return sha512prefix + random_letters
|
||||||
|
|
||||||
|
|
||||||
|
def lock_running(lock_file):
|
||||||
|
"""Tries to acquire app lock
|
||||||
|
|
||||||
|
:param lock_file: a path to a file for locking
|
||||||
|
|
||||||
|
:returns: True in case of success, False, if lock's already held
|
||||||
|
"""
|
||||||
|
global lock_file_obj
|
||||||
|
lock_file_obj = open(lock_file, "w")
|
||||||
|
try:
|
||||||
|
fcntl.lockf(lock_file_obj, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||||
|
return True
|
||||||
|
except IOError:
|
||||||
|
print("Another copy of fuelmenu is running. "
|
||||||
|
"Please exit it and try again.", file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
|
@ -21,6 +21,8 @@ PUPPET_LOGFILE = "/var/log/puppet/fuelmenu-puppet.log"
|
||||||
SETTINGS_FILE = "/etc/fuel/astute.yaml"
|
SETTINGS_FILE = "/etc/fuel/astute.yaml"
|
||||||
RELEASE_FILE = "/etc/fuel_release"
|
RELEASE_FILE = "/etc/fuel_release"
|
||||||
|
|
||||||
|
DEFAULT_LOCK_FILE = "/var/run/fuelmenu.lock"
|
||||||
|
|
||||||
PRE_DEPLOYMENT_MODE = "pre"
|
PRE_DEPLOYMENT_MODE = "pre"
|
||||||
POST_DEPLOYMENT_MODE = "post"
|
POST_DEPLOYMENT_MODE = "post"
|
||||||
|
|
||||||
|
|
|
@ -469,8 +469,17 @@ def main(*args, **kwargs):
|
||||||
parser.add_option("-i", "--iface", dest="iface", metavar="IFACE",
|
parser.add_option("-i", "--iface", dest="iface", metavar="IFACE",
|
||||||
default=default_iface, help="Set IFACE as primary.")
|
default=default_iface, help="Set IFACE as primary.")
|
||||||
|
|
||||||
|
parser.add_option("-l", "--lock-file",
|
||||||
|
default=consts.DEFAULT_LOCK_FILE,
|
||||||
|
help="Path to the process lock file. If unspecified, "
|
||||||
|
"the default {} is used."
|
||||||
|
.format(consts.DEFAULT_LOCK_FILE))
|
||||||
|
|
||||||
options, args = parser.parse_args()
|
options, args = parser.parse_args()
|
||||||
|
|
||||||
|
if not utils.lock_running(options.lock_file):
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
if not network.is_interface_has_ip(options.iface):
|
if not network.is_interface_has_ip(options.iface):
|
||||||
print("Selected interface '{0}' has no assigned IP. "
|
print("Selected interface '{0}' has no assigned IP. "
|
||||||
"Could not start.".format(options.iface))
|
"Could not start.".format(options.iface))
|
||||||
|
|
|
@ -14,6 +14,10 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import tempfile
|
||||||
|
|
||||||
from fuelmenu.common import utils
|
from fuelmenu.common import utils
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
@ -73,3 +77,54 @@ class TestUtils(unittest.TestCase):
|
||||||
mocked_open.side_effect = IOError()
|
mocked_open.side_effect = IOError()
|
||||||
data = utils.get_fuel_version()
|
data = utils.get_fuel_version()
|
||||||
self.assertEqual("", data)
|
self.assertEqual("", data)
|
||||||
|
|
||||||
|
def test_lock_running(self):
|
||||||
|
lock_file = tempfile.mktemp()
|
||||||
|
self.assertTrue(utils.lock_running(lock_file))
|
||||||
|
|
||||||
|
def test_lock_running_fail(self):
|
||||||
|
|
||||||
|
def handler(signum, frame):
|
||||||
|
raise Exception("Timeout occured while running unit test "
|
||||||
|
"test_lock_running_fail")
|
||||||
|
|
||||||
|
# set an alarm, because test may hang
|
||||||
|
signal.signal(signal.SIGALRM, handler)
|
||||||
|
signal.setitimer(signal.ITIMER_REAL, 3)
|
||||||
|
|
||||||
|
lock_file = tempfile.mktemp()
|
||||||
|
|
||||||
|
read_fd1, write_fd1 = os.pipe()
|
||||||
|
read_fd2, write_fd2 = os.pipe()
|
||||||
|
pid = os.fork()
|
||||||
|
if pid == 0:
|
||||||
|
# Run lock_running in child first
|
||||||
|
os.close(read_fd1)
|
||||||
|
os.close(write_fd2)
|
||||||
|
write_f1 = os.fdopen(write_fd1, 'w')
|
||||||
|
read_f2 = os.fdopen(read_fd2, 'r')
|
||||||
|
|
||||||
|
utils.lock_running(lock_file)
|
||||||
|
|
||||||
|
write_f1.write('x')
|
||||||
|
write_f1.close()
|
||||||
|
read_f2.read()
|
||||||
|
|
||||||
|
# exit from child by issuing execve, so that unit
|
||||||
|
# testing framework will not finish in two instances
|
||||||
|
os.execlp('true', 'true')
|
||||||
|
else:
|
||||||
|
# then in parent
|
||||||
|
os.close(write_fd1)
|
||||||
|
os.close(read_fd2)
|
||||||
|
read_f1 = os.fdopen(read_fd1, 'r')
|
||||||
|
write_f2 = os.fdopen(write_fd2, 'w')
|
||||||
|
read_f1.read()
|
||||||
|
|
||||||
|
# child is holding lock at this point
|
||||||
|
self.assertFalse(utils.lock_running(lock_file))
|
||||||
|
|
||||||
|
write_f2.write('x')
|
||||||
|
write_f2.close()
|
||||||
|
|
||||||
|
signal.alarm(0)
|
||||||
|
|
Loading…
Reference in New Issue