move file locking into a utility module with logging

This commit is contained in:
Michael Hudson-Doyle 2020-05-01 09:57:59 +12:00
parent 5edfddabf5
commit adb8e2ac43
4 changed files with 65 additions and 13 deletions

View File

@ -14,7 +14,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import asyncio import asyncio
import fcntl
import json import json
import logging import logging
import os import os
@ -134,9 +133,7 @@ class FilesystemController(SubiquityController):
async def _probe(self): async def _probe(self):
with self.context.child("_probe") as context: with self.context.child("_probe") as context:
await run_in_thread( async with self.app.install_lock_file.shared():
fcntl.flock, self.app.install_lock_file, fcntl.LOCK_SH)
try:
self._crash_reports = {} self._crash_reports = {}
if isinstance(self.ui.body, ProbingFailed): if isinstance(self.ui.body, ProbingFailed):
self.ui.set_body(SlowProbing(self)) self.ui.set_body(SlowProbing(self))
@ -166,8 +163,6 @@ class FilesystemController(SubiquityController):
self._crash_reports[restricted] = report self._crash_reports[restricted] = report
continue continue
break break
finally:
fcntl.flock(self.app.install_lock_file, fcntl.LOCK_UN)
def convert_autoinstall_config(self): def convert_autoinstall_config(self):
log.debug("self.ai_data = %s", self.ai_data) log.debug("self.ai_data = %s", self.ai_data)

View File

@ -16,7 +16,6 @@
import asyncio import asyncio
import contextlib import contextlib
import datetime import datetime
import fcntl
import logging import logging
import os import os
import re import re
@ -281,13 +280,9 @@ class InstallProgressController(SubiquityController):
log.debug('curtin install cmd: {}'.format(curtin_cmd)) log.debug('curtin install cmd: {}'.format(curtin_cmd))
await run_in_thread( async with self.app.install_lock_file.exclusive():
fcntl.flock, self.app.install_lock_file, fcntl.LOCK_EX)
try:
cp = await arun_command( cp = await arun_command(
self.logged_command(curtin_cmd), check=True) self.logged_command(curtin_cmd), check=True)
finally:
fcntl.flock(self.app.install_lock_file, fcntl.LOCK_UN)
log.debug('curtin_install completed: %s', cp.returncode) log.debug('curtin_install completed: %s', cp.returncode)

View File

@ -39,6 +39,7 @@ from subiquitycore.core import Application
from subiquity.controllers.error import ( from subiquity.controllers.error import (
ErrorReportKind, ErrorReportKind,
) )
from subiquity.lockfile import Lockfile
from subiquity.models.subiquity import SubiquityModel from subiquity.models.subiquity import SubiquityModel
from subiquity.snapd import ( from subiquity.snapd import (
AsyncSnapd, AsyncSnapd,
@ -123,7 +124,7 @@ class Subiquity(Application):
self.controllers.remove("Zdev") self.controllers.remove("Zdev")
super().__init__(opts) super().__init__(opts)
self.install_lock_file = open(self.state_path("installing"), 'w') self.install_lock_file = Lockfile(self.state_path("installing"))
self.block_log_dir = block_log_dir self.block_log_dir = block_log_dir
self.kernel_cmdline = shlex.split(opts.kernel_cmdline) self.kernel_cmdline = shlex.split(opts.kernel_cmdline)
if opts.snaps_from_examples: if opts.snaps_from_examples:

61
subiquity/lockfile.py Normal file
View File

@ -0,0 +1,61 @@
# Copyright 2020 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import fcntl
import logging
from subiquitycore.async_helpers import run_in_thread
log = logging.getLogger('subiquity.lockfile')
class _LockContext:
def __init__(self, lockfile, flags):
self.lockfile = lockfile
self.flags = flags
self._kind = "???"
if flags & fcntl.LOCK_EX:
self._kind = "exclusive"
elif flags & fcntl.LOCK_SH:
self._kind = "shared"
def __enter__(self):
log.debug("locking %s %s", self._kind, self.lockfile.path)
fcntl.flock(self.lockfile.fp, self.flags)
return self
async def __aenter__(self):
return await run_in_thread(self.__enter__)
def __exit__(self, etype, evalue, etb):
log.debug("unlocking %s %s", self._kind, self.lockfile.path)
fcntl.flock(self.lockfile.fp, fcntl.LOCK_UN)
async def __aexit__(self, etype, evalue, etb):
self.__exit__(etype, evalue, etb)
class Lockfile:
def __init__(self, path):
self.path = path
self.fp = open(path, 'w')
def exclusive(self):
return _LockContext(self, fcntl.LOCK_EX)
def shared(self):
return _LockContext(self, fcntl.LOCK_SH)