/usr/lib/python3/dist-packages/plainbox/impl/session/manager.py is in python3-plainbox 0.5.3-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | # This file is part of Checkbox.
#
# Copyright 2012, 2013 Canonical Ltd.
# Written by:
# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
#
# Checkbox is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3,
# as published by the Free Software Foundation.
#
# Checkbox 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
"""
:mod:`plainbox.impl.session.manager` -- manager for sessions
============================================================
This module contains glue code that allows one to create and manage sessions
and their filesystem presence. It allows
:class:`~plainbox.impl.session.state.SessionState` to be de-coupled
from :class:`~plainbox.impl.session.storage.SessionStorageRepository`,
:class:`~plainbox.impl.session.storage.SessionStorage`,
:class:`~plainbox.impl.session.suspend.SessionSuspendHelper`
and :class:`~plainbox.impl.session.suspend.SessionResumeHelper`.
"""
import errno
import logging
import os
from plainbox.i18n import gettext as _, ngettext
from plainbox.impl.session.resume import SessionResumeHelper
from plainbox.impl.session.state import SessionState
from plainbox.impl.session.storage import LockedStorageError
from plainbox.impl.session.storage import SessionStorage
from plainbox.impl.session.storage import SessionStorageRepository
from plainbox.impl.session.suspend import SessionSuspendHelper
logger = logging.getLogger("plainbox.session.manager")
class WellKnownDirsHelper:
"""
Helper class that knows about well known directories for SessionStorage.
This class simply gets rid of various magic directory names that we
associate with session storage. It also provides a convenience utility
method :meth:`populate()` to create all of those directories, if needed.
"""
def __init__(self, storage):
# assert isinstance(storage, SessionStorage)
self._storage = storage
@property
def storage(self):
"""
:class:`~plainbox.impl.session.storage.SessionStorage` associated with
this helper
"""
return self._storage
def populate(self):
"""
Create all of the well known directories that are expected to exist
inside a freshly created session storage directory
"""
for dirname in self.all_directories:
if not os.path.exists(dirname):
os.makedirs(dirname)
@property
def all_directories(self):
"""
a list of all well-known directories
"""
return [self.io_log_pathname]
@property
def io_log_pathname(self):
"""
full path of the directory where per-job IO logs are stored
"""
return os.path.join(self.storage.location, "io-logs")
class SessionManager:
"""
Manager class for coupling SessionStorage with SessionState.
This class allows application code to manage disk state of sessions. Using
the :meth:`checkpoint()` method applications can create persistent
snapshots of the :class:`~plainbox.impl.session.state.SessionState`
associated with each :class:`SessionManager`.
"""
def __init__(self, state, storage):
"""
Initialize a manager with a specific
:class:`~plainbox.impl.session.state.SessionState` and
:class:`~plainbox.impl.session.storage.SessionStorage`.
"""
# assert isinstance(state, SessionState)
# assert isinstance(storage, SessionStorage)
self._state = state
self._storage = storage
logger.debug(
# TRANSLATORS: please don't translate 'SessionManager' 'state' and
# 'storage'
_("Created SessionManager with state:%r and storage:%r"),
state, storage)
@property
def state(self):
"""
:class:`~plainbox.impl.session.state.SessionState` associated with
this manager
"""
return self._state
@property
def storage(self):
"""
:class:`~plainbox.impl.session.storage.SessionStorage` associated with
this manager
"""
return self._storage
@classmethod
def create_with_state(cls, state, repo=None, legacy_mode=False):
"""
Create a session manager by wrapping existing session state.
This method populates the session storage with all of the well known
directories (using :meth:`WellKnownDirsHelper.populate()`)
:param stage:
A pre-existing SessioState object.
:param repo:
If specified then this particular repository will be used to create
the storage for this session. If left out, a new repository is
constructed with the default location.
:ptype repo:
:class:`~plainbox.impl.session.storage.SessionStorageRepository`.
:param legacy_mode:
Propagated to
:meth:`~plainbox.impl.session.storage.SessionStorage.create()`
to ensure that legacy (single session) mode is used.
:ptype legacy_mode:
bool
:return:
fresh :class:`SessionManager` instance
"""
logger.debug("SessionManager.create_with_state()")
if repo is None:
repo = SessionStorageRepository()
storage = SessionStorage.create(repo.location, legacy_mode)
WellKnownDirsHelper(storage).populate()
return cls(state, storage)
@classmethod
def create_with_job_list(cls, job_list=None, repo=None, legacy_mode=False):
"""
Create a session manager with a fresh session.
This method populates the session storage with all of the well known
directories (using :meth:`WellKnownDirsHelper.populate()`)
:param job_list:
If specified then this will be the initial list of jobs known
by the session state object. This can be specified for convenience
but is really optional since the application can always add more
jobs to an existing session.
:ptype job_list:
list of :class:`~plainbox.abc.IJobDefinition`.
:param repo:
If specified then this particular repository will be used to create
the storage for this session. If left out, a new repository is
constructed with the default location.
:ptype repo:
:class:`~plainbox.impl.session.storage.SessionStorageRepository`.
:param legacy_mode:
Propagated to
:meth:`~plainbox.impl.session.storage.SessionStorage.create()`
to ensure that legacy (single session) mode is used.
:ptype legacy_mode:
bool
:return:
fresh :class:`SessionManager` instance
"""
logger.debug("SessionManager.create_session()")
if job_list is None:
job_list = []
state = SessionState(job_list)
if repo is None:
repo = SessionStorageRepository()
storage = SessionStorage.create(repo.location, legacy_mode)
WellKnownDirsHelper(storage).populate()
return cls(state, storage)
@classmethod
def load_session(cls, job_list, storage, early_cb=None):
"""
Load a previously checkpointed session.
This method allows one to re-open a session that was previously
created by :meth:`SessionManager.checkpoint()`
:param job_list:
List of all known jobs. This argument is used to reconstruct the
session from a dormant state. Since the suspended data cannot
capture implementation details of each job reliably actual jobs
need to be provided externally. Unlike in :meth:`create_session()`
this list really needs to be complete, it must also include
any generated jobs.
:param storage:
The storage that should be used for this particular session.
The storage object holds references to existing directories
in the file system. When restoring an existing dormant session
it is important to use the correct storage object, the one that
corresponds to the file system location used be the session
before it was saved.
:ptype storage:
:class:`~plainbox.impl.session.storage.SessionStorage`
:param early_cb:
A callback that allows the caller to "see" the session object
early, before the bulk of resume operation happens. This method can
be used to register callbacks on the new session before this method
call returns. The callback accepts one argument, session, which is
being resumed. This is being passed directly to
:meth:`plainbox.impl.session.resume.SessionResumeHelper.resume()`
:raises:
Anything that can be raised by
:meth:`~plainbox.impl.session.storage.SessionStorage.
load_checkpoint()` and :meth:`~plainbox.impl.session.suspend.
SessionResumeHelper.resume()`
:returns:
Fresh instance of :class:`SessionManager`
"""
logger.debug("SessionManager.load_session()")
try:
data = storage.load_checkpoint()
except IOError as exc:
if exc.errno == errno.ENOENT:
state = SessionState(job_list)
else:
raise
else:
state = SessionResumeHelper(job_list).resume(data, early_cb)
return cls(state, storage)
def checkpoint(self):
"""
Create a checkpoint of the session.
After calling this method you can later reopen the same session with
:meth:`SessionManager.load_session()`.
"""
logger.debug("SessionManager.checkpoint()")
data = SessionSuspendHelper().suspend(self.state)
logger.debug(
ngettext(
"Saving %d byte of checkpoint data to %r",
"Saving %d bytes of checkpoint data to %r", len(data)
), len(data), self.storage.location)
try:
self.storage.save_checkpoint(data)
except LockedStorageError:
self.storage.break_lock()
self.storage.save_checkpoint(data)
def destroy(self):
"""
Destroy all of the filesystem artifacts of the session.
This basically calls
:meth:`~plainbox.impl.session.storage.SessionStorage.remove()`
"""
logger.debug("SessionManager.destroy()")
self.storage.remove()
|