Add sysupgrade state file

When IPA package is being updated, some of the configuration files
are also updated. Sometimes it may be useful to store upgrade meta
information for next package upgrades. For example an information
that some config file was already updated and we don't want to
update it again if user purposedly reverted the change.

This patch adds a new StateFile in /var/lib/ipa/sysupgrade which
is capable of holding this information. New sysupgrade.py module
was created to provide simple API to access the upgrade state
information.
This commit is contained in:
Martin Kosek
2012-06-08 08:31:37 +02:00
committed by Rob Crittenden
parent 4507dcda58
commit c856fb6073
5 changed files with 91 additions and 13 deletions

View File

@@ -357,6 +357,7 @@ rm %{buildroot}/%{_libdir}/samba/pdb/ipasam.la
# and link back. # and link back.
mkdir -p %{buildroot}/%{_sysconfdir}/ipa/html mkdir -p %{buildroot}/%{_sysconfdir}/ipa/html
mkdir -p %{buildroot}/%{_localstatedir}/cache/ipa/sysrestore mkdir -p %{buildroot}/%{_localstatedir}/cache/ipa/sysrestore
mkdir -p %{buildroot}/%{_localstatedir}/cache/ipa/sysupgrade
mkdir %{buildroot}%{_usr}/share/ipa/html/ mkdir %{buildroot}%{_usr}/share/ipa/html/
ln -s ../../../..%{_sysconfdir}/ipa/html/ssbrowser.html \ ln -s ../../../..%{_sysconfdir}/ipa/html/ssbrowser.html \
%{buildroot}%{_usr}/share/ipa/html/ssbrowser.html %{buildroot}%{_usr}/share/ipa/html/ssbrowser.html
@@ -620,6 +621,7 @@ fi
%attr(755,root,root) %{plugin_dir}/libipa_cldap.so %attr(755,root,root) %{plugin_dir}/libipa_cldap.so
%dir %{_localstatedir}/lib/ipa %dir %{_localstatedir}/lib/ipa
%attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore
%attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysupgrade
%dir %{_localstatedir}/cache/ipa %dir %{_localstatedir}/cache/ipa
%attr(700,apache,apache) %dir %{_localstatedir}/cache/ipa/sessions %attr(700,apache,apache) %dir %{_localstatedir}/cache/ipa/sessions
%attr(755,root,root) %{_libdir}/krb5/plugins/kdb/ipadb.so %attr(755,root,root) %{_libdir}/krb5/plugins/kdb/ipadb.so
@@ -701,6 +703,9 @@ fi
%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt
%changelog %changelog
* Fri Jun 8 2012 Martin Kosek <mkosek@redhat.com> - 2.99.0-32
- Add directory /var/lib/ipa/sysupgrade for package upgrade metadata
* Mon Jun 4 2012 Alexander Bokovoy <abokovoy@redhat.com> - 2.99.0-31 * Mon Jun 4 2012 Alexander Bokovoy <abokovoy@redhat.com> - 2.99.0-31
- Add python-crypto to build dependencies for AD server-side code - Add python-crypto to build dependencies for AD server-side code

View File

@@ -19,11 +19,14 @@ SUBDIRS = \
install-exec-local: install-exec-local:
mkdir -p $(DESTDIR)$(localstatedir)/lib/ipa/sysrestore mkdir -p $(DESTDIR)$(localstatedir)/lib/ipa/sysrestore
chmod 700 $(DESTDIR)$(localstatedir)/lib/ipa/sysrestore chmod 700 $(DESTDIR)$(localstatedir)/lib/ipa/sysrestore
mkdir -p $(DESTDIR)$(localstatedir)/lib/ipa/sysupgrade
chmod 700 $(DESTDIR)$(localstatedir)/lib/ipa/sysupgrade
mkdir -p $(DESTDIR)$(localstatedir)/cache/ipa/sessions mkdir -p $(DESTDIR)$(localstatedir)/cache/ipa/sessions
chmod 700 $(DESTDIR)$(localstatedir)/cache/ipa/sessions chmod 700 $(DESTDIR)$(localstatedir)/cache/ipa/sessions
uninstall-local: uninstall-local:
-rmdir $(DESTDIR)$(localstatedir)/lib/ipa/sysrestore -rmdir $(DESTDIR)$(localstatedir)/lib/ipa/sysrestore
-rmdir $(DESTDIR)$(localstatedir)/lib/ipa/sysupgrade
-rmdir $(DESTDIR)$(localstatedir)/lib/ipa -rmdir $(DESTDIR)$(localstatedir)/lib/ipa
-rmdir $(DESTDIR)$(localstatedir)/cache/ipa/sessions -rmdir $(DESTDIR)$(localstatedir)/cache/ipa/sessions
-rmdir $(DESTDIR)$(localstatedir)/cache/ipa -rmdir $(DESTDIR)$(localstatedir)/cache/ipa

View File

@@ -48,6 +48,7 @@ from ipaserver.install import ntpinstance
from ipaserver.install import certs from ipaserver.install import certs
from ipaserver.install import cainstance from ipaserver.install import cainstance
from ipaserver.install import memcacheinstance from ipaserver.install import memcacheinstance
from ipaserver.install import sysupgrade
from ipaserver.install import service, installutils from ipaserver.install import service, installutils
from ipapython import version from ipapython import version
@@ -495,6 +496,9 @@ def uninstall():
except CalledProcessError, e: except CalledProcessError, e:
print >>sys.stderr, "Failed to set this machine hostname back to %s (%s)." % (old_hostname, str(e)) print >>sys.stderr, "Failed to set this machine hostname back to %s (%s)." % (old_hostname, str(e))
# remove upgrade state file
sysupgrade.remove_upgrade_file()
if fstore.has_files(): if fstore.has_files():
root_logger.error('Some files have not been restored, see /var/lib/ipa/sysrestore/sysrestore.index') root_logger.error('Some files have not been restored, see /var/lib/ipa/sysrestore/sysrestore.index')
has_state = False has_state = False

View File

@@ -41,7 +41,7 @@ SYSRESTORE_STATEFILE = "sysrestore.state"
class FileStore: class FileStore:
"""Class for handling backup and restore of files""" """Class for handling backup and restore of files"""
def __init__(self, path = SYSRESTORE_PATH): def __init__(self, path = SYSRESTORE_PATH, index_file = SYSRESTORE_INDEXFILE):
"""Create a _StoreFiles object, that uses @path as the """Create a _StoreFiles object, that uses @path as the
base directory. base directory.
@@ -49,7 +49,7 @@ class FileStore:
about the original location of the saved files. about the original location of the saved files.
""" """
self._path = path self._path = path
self._index = self._path + "/" + SYSRESTORE_INDEXFILE self._index = os.path.join(self._path, index_file)
self.random = random.Random() self.random = random.Random()
@@ -279,7 +279,7 @@ class StateFile:
enabled=False enabled=False
""" """
def __init__(self, path = SYSRESTORE_PATH): def __init__(self, path = SYSRESTORE_PATH, state_file = SYSRESTORE_STATEFILE):
"""Create a StateFile object, loading from @path. """Create a StateFile object, loading from @path.
The dictionary @modules, a member of the returned object, The dictionary @modules, a member of the returned object,
@@ -290,7 +290,7 @@ class StateFile:
The keys in these latter dictionaries are arbitrary strings The keys in these latter dictionaries are arbitrary strings
and the values may either be strings or booleans. and the values may either be strings or booleans.
""" """
self._path = path+"/"+SYSRESTORE_STATEFILE self._path = os.path.join(path, state_file)
self.modules = {} self.modules = {}
@@ -359,6 +359,31 @@ class StateFile:
self.save() self.save()
def get_state(self, module, key):
"""Return the value of an item of system state from @module,
identified by the string @key.
If the item doesn't exist, #None will be returned, otherwise
the original string or boolean value is returned.
"""
if not self.modules.has_key(module):
return None
return self.modules[module].get(key, None)
def delete_state(self, module, key):
"""Delete system state from @module, identified by the string
@key.
If the item doesn't exist, no change is done.
"""
try:
del self.modules[module][key]
except KeyError:
pass
else:
self.save()
def restore_state(self, module, key): def restore_state(self, module, key):
"""Return the value of an item of system state from @module, """Return the value of an item of system state from @module,
identified by the string @key, and remove it from the backed identified by the string @key, and remove it from the backed
@@ -368,16 +393,10 @@ class StateFile:
the original string or boolean value is returned. the original string or boolean value is returned.
""" """
if not self.modules.has_key(module): value = self.get_state(module, key)
return None
if not self.modules[module].has_key(key): if value is not None:
return None self.delete_state(module, key)
value = self.modules[module][key]
del self.modules[module][key]
self.save()
return value return value

View File

@@ -0,0 +1,47 @@
# Authors: Martin Kosek <mkosek@redhat.com>
#
# Copyright (C) 2012 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import os
import os.path
from ipapython import sysrestore
from ipapython.ipa_log_manager import *
STATEFILE_DIR = '/var/lib/ipa/sysupgrade'
STATEFILE_FILE = 'sysupgrade.state'
_sstore = sysrestore.StateFile(STATEFILE_DIR, STATEFILE_FILE)
def get_upgrade_state(module, state):
global _sstore
return _sstore.get_state(module, state)
def set_upgrade_state(module, state, value):
global _sstore
_sstore.backup_state(module, state, value)
def remove_upgrade_state(module, state):
global _sstore
_sstore.delete_state(module, state)
def remove_upgrade_file():
try:
os.remove(os.path.join(STATEFILE_DIR, STATEFILE_FILE))
except Exception, e:
root_logger.debug('Cannot remove sysupgrade state file: %s', e)