--- a/src/modules/client/imageplan.py Mon Mar 24 10:12:12 2014 -0700
+++ b/src/modules/client/imageplan.py Wed Mar 26 10:39:37 2014 -0700
@@ -237,6 +237,16 @@
"""get the (approx) number of download space available"""
return self.pd._cbytes_avail
+ def __finish_plan(self, pdstate, fmri_changes=None):
+ """Private helper function that must be called at the end of
+ every planning operation to ensure final plan state is set and
+ any general post-plan work is performed."""
+
+ pd = self.pd
+ pd.state = pdstate
+ if not fmri_changes is None:
+ pd._fmri_changes = fmri_changes
+
def __vector_2_fmri_changes(self, installed_dict, vector,
li_pkg_updates=True, new_variants=None, new_facets=None,
fmri_changes=None):
@@ -510,7 +520,7 @@
new_variants=new_variants,
pkgs_inst=pkgs_inst,
reject_list=reject_list)
- self.pd.state = plandesc.EVALUATED_PKGS
+ self.__finish_plan(plandesc.EVALUATED_PKGS)
def __plan_exact_install(self, li_pkg_updates=True, li_sync_op=False,
new_facets=None, new_variants=None, pkgs_inst=None,
@@ -528,7 +538,7 @@
pkgs_inst=pkgs_inst,
reject_list=reject_list,
exact_install=True)
- self.pd.state = plandesc.EVALUATED_PKGS
+ self.__finish_plan(plandesc.EVALUATED_PKGS)
def set_be_options(self, backup_be, backup_be_name, new_be,
be_activate, be_name):
@@ -696,7 +706,7 @@
new_variants=new_variants,
reject_list=reject_list,
fmri_changes=fmri_changes)
- self.pd.state = plandesc.EVALUATED_PKGS
+ self.__finish_plan(plandesc.EVALUATED_PKGS)
# evaluate what varcet changes are required
new_variants, new_facets, \
@@ -749,8 +759,9 @@
# If solver isn't involved, assume the list of packages
# has been determined.
assert fmri_changes is not None
- self.pd._fmri_changes = fmri_changes
- self.pd.state = plandesc.EVALUATED_PKGS
+ self.__finish_plan(plandesc.EVALUATED_PKGS,
+ fmri_changes=fmri_changes)
+
def plan_set_mediators(self, new_mediators):
"""Determine the changes needed to set the specified mediators.
@@ -888,7 +899,7 @@
self.pd._new_mediators = update_mediators
pt.plan_done(pt.PLAN_MEDIATION_CHG)
- self.pd.state = plandesc.EVALUATED_PKGS
+ self.__finish_plan(plandesc.EVALUATED_PKGS)
def __any_reject_matches(self, reject_list):
"""Check if any reject patterns match installed packages (in
@@ -920,8 +931,8 @@
# don't bother invoking the solver.
if not uninstall and not new_facets is not None and insync:
# we don't need to do anything
- self.pd._fmri_changes = []
- self.pd.state = plandesc.EVALUATED_PKGS
+ self.__finish_plan(plandesc.EVALUATED_PKGS,
+ fmri_changes=[])
return
self.__plan_install(li_pkg_updates=li_pkg_updates,
@@ -982,7 +993,7 @@
if DebugValues["plan"]:
self.pd._solver_errors = solver.get_trim_errors()
- self.pd.state = plandesc.EVALUATED_PKGS
+ self.__finish_plan(plandesc.EVALUATED_PKGS)
def __plan_update_solver(self, pkgs_update=None,
ignore_missing=False, reject_list=misc.EmptyI):
@@ -1077,7 +1088,7 @@
ignore_missing=ignore_missing,
pkgs_update=pkgs_update,
reject_list=reject_list)
- self.pd.state = plandesc.EVALUATED_PKGS
+ self.__finish_plan(plandesc.EVALUATED_PKGS)
def plan_revert(self, args, tagged):
"""Plan reverting the specified files or files tagged as
@@ -1219,10 +1230,9 @@
can_exclude=True)
self.pd.pkg_plans.append(pp)
- self.pd._fmri_changes = []
-
pt.plan_done(pt.PLAN_PKGPLAN)
pt.plan_all_done()
+ self.__finish_plan(plandesc.EVALUATED_PKGS, fmri_changes=[])
def __gen_matching_acts(self, path, pattern):
# return two lists of actions that match pattern at path
@@ -2528,6 +2538,272 @@
else:
d.setdefault(name, []).append(value)
+ def __evaluate_pkg_preserved_files(self):
+ """Private helper function that determines which preserved files
+ have changed in ImagePlan and how."""
+
+ assert self.state >= plandesc.MERGED_OK
+
+ pd = self.pd
+
+ # Track movement of preserved ("editable") files for plan
+ # summary and cache management.
+ moved = []
+ removed = []
+ installed = []
+ updated = []
+
+ # __merge_actions() adds the 'save_file' attribute to src
+ # actions that are being moved somewhere else and to dest
+ # actions that will be restored from a src action. This only
+ # happens when at least one of the files involved has a
+ # 'preserve' attribute, so it's safe to treat either as a
+ # 'preserved' ("editable") file.
+
+ # The removal_actions are processed first since we'll determine
+ # how to transform them while processing the install and update
+ # actions based on the destination file state.
+ for ap in pd.removal_actions:
+ src = ap.src
+ if src.name != "file":
+ continue
+ if not ("preserve" in src.attrs or
+ "save_file" in src.attrs or
+ "overlay" in src.attrs):
+ # Removed action has to be a preserved file or a
+ # source of a restore.
+ continue
+ if "elfhash" in src.attrs:
+ # Ignore erroneously tagged files.
+ continue
+
+ entry = [src.attrs["path"]]
+ save_file = src.attrs.get("save_file")
+ if save_file:
+ entry.append(save_file[0])
+ entry.append(src)
+ removed.append(entry)
+
+ for ap in itertools.chain(pd.install_actions,
+ pd.update_actions):
+ orig = ap.src
+ dest = ap.dst
+ if dest.name != "file":
+ continue
+ if not ((orig and ("preserve" in orig.attrs or
+ "save_file" in orig.attrs or
+ "overlay" in orig.attrs)) or
+ ("preserve" in dest.attrs or
+ "save_file" in dest.attrs or
+ "overlay" in dest.attrs)):
+ # At least one of the actions has to be a
+ # preserved file or a target of a restore.
+ continue
+ if "elfhash" in dest.attrs:
+ # Ignore erroneously tagged files.
+ continue
+
+ tpath = dest.attrs["path"]
+ entry = [tpath]
+ save_file = dest.attrs.get("save_file")
+ if save_file:
+ tcache_name = save_file[0]
+ for (ridx, rentry) in enumerate(removed):
+ if len(rentry) == 1:
+ continue
+
+ rpath, rcache_name, rorig = rentry
+ if rcache_name == tcache_name:
+ # If the cache name for this new
+ # file matches one of those for
+ # a removed file, the removed
+ # file will be renamed to this
+ # action's path before the
+ # action is processed.
+ del removed[ridx]
+ save_file = rpath
+ orig = rorig
+ break
+ else:
+ save_file = None
+
+ if not orig:
+ # We can't rely on _check_preserve for this case
+ # as there's no existing on-disk file at the
+ # destination path yet.
+ if dest.attrs.get("preserve") != "legacy":
+ # 'legacy' actions are only delivered if
+ # we're updating something already
+ # installed or moving an existing file.
+ installed.append(entry)
+ continue
+ elif orig.name != "file":
+ # File is being replaced with another object
+ # type.
+ updated.append(entry)
+ continue
+
+ # The order of these checks is significant in
+ # determining how a preserved file changed!
+ #
+ # First, check for on-disk content changes.
+ opath = orig.get_installed_path(self.image.get_root())
+ pres_type = dest._check_preserve(orig, ap.p,
+ orig_path=opath)
+
+ final_path = dest.get_installed_path(
+ self.image.get_root())
+
+ # If a removed action is going to be restored to
+ # complete the operation, show the removed action path
+ # as the source for the move omitting the steps
+ # in-between. For example:
+ # moved: testme -> newme
+ # moved: newme -> newme.legacy
+ # installed: newme
+ # ...becomes:
+ # moved: testme -> newme.legacy
+ # installed: newme
+ if save_file:
+ mpath = save_file
+ else:
+ mpath = tpath
+
+ if pres_type == "renameold":
+ moved.append([mpath, tpath + ".old"])
+ installed.append(entry)
+ continue
+ elif pres_type == "renameold.update":
+ moved.append([mpath, tpath + ".update"])
+ installed.append(entry)
+ continue
+ elif pres_type == "legacy":
+ if orig.attrs.get("preserve") == "legacy":
+ updated.append(entry)
+ continue
+ # Move only happens on preserve transition and
+ # only if original already exists.
+ if os.path.isfile(opath):
+ moved.append([mpath, tpath + ".legacy"])
+ installed.append(entry)
+ continue
+ elif pres_type == True and save_file:
+ # If the source and destination path are the
+ # same, the content won't be updated.
+ if mpath != tpath:
+ # New content ignored in favour of old.
+ moved.append([mpath, tpath])
+ continue
+
+ # Next, if on-disk file will be preserved and some other
+ # unique_attr is changing (such as mode, etc.) mark the
+ # file as "updated".
+ if (pres_type == True and
+ ImagePlan.__find_inconsistent_attrs(
+ ((orig,), (dest,)), ignore=("path",))):
+ updated.append(entry)
+ continue
+
+ # For remaining cases, what happens is based on the
+ # result of _check_preserve().
+ if pres_type == "renamenew":
+ if save_file:
+ moved.append([mpath, tpath])
+ # Delivered content changed.
+ installed.append([tpath + ".new"])
+ elif pres_type is None:
+ # Delivered content or unique_attrs changed.
+ updated.append(entry)
+ elif pres_type == False:
+ if save_file:
+ moved.append([mpath, tpath])
+ continue
+
+ if not os.path.isfile(final_path):
+ # File is missing or of wrong type.
+ installed.append(entry)
+ continue
+
+ # If a file is moving between packages, it will
+ # appear as an update, but may not have not have
+ # different content or unique_attrs. Check to
+ # see if it does.
+ if ImagePlan.__find_inconsistent_attrs(
+ ((orig,), (dest,)), ignore=("path",)):
+ # Different unique_attrs.
+ updated.append(entry)
+ continue
+
+ attr, shash, ohash, hfunc = \
+ digest.get_common_preferred_hash(dest, orig)
+ if shash != ohash:
+ # Delivered content changed.
+ updated.append(entry)
+ continue
+
+ # Pre-sort results for consumers.
+ installed.sort()
+ moved.sort()
+ removed.sort()
+ updated.sort()
+
+ self.pd._preserved = {
+ "installed": installed,
+ "moved": moved,
+ "removed": removed,
+ "updated": updated,
+ }
+
+ def __evaluate_pkg_downloads(self):
+ """Private helper function that determines package data to be
+ downloaded and updates the plan accordingly."""
+
+ assert self.state >= plandesc.MERGED_OK
+
+ pd = self.pd
+
+ for p in pd.pkg_plans:
+ cpbytes, pbytes = p.get_bytes_added()
+ if p.destination_fmri:
+ mpath = self.image.get_manifest_path(
+ p.destination_fmri)
+ try:
+ # Manifest data is essentially stored
+ # three times (original, cache, catalog).
+ # For now, include this in cbytes_added
+ # since that's closest to where the
+ # download cache is stored.
+ pd._cbytes_added += \
+ os.stat(mpath).st_size * 3
+ except EnvironmentError, e:
+ raise api_errors._convert_error(e)
+ pd._cbytes_added += cpbytes
+ pd._bytes_added += pbytes
+
+ # Include state directory in cbytes_added for now since it's
+ # closest to where the download cache is stored. (Twice the
+ # amount is used because image state update involves using
+ # a complete copy of existing state.)
+ pd._cbytes_added += misc.get_dir_size(self.image._statedir) * 2
+
+ # Our slop factor is 25%; overestimating is safer than under-
+ # estimating. This attempts to approximate how much overhead
+ # the filesystem will impose on the operation. Empirical
+ # testing suggests that overhead can vary wildly depending on
+ # average file size, fragmentation, zfs metadata overhead, etc.
+ # For an install of a package such as solaris-small-server into
+ # an image, a 12% difference between actual size and installed
+ # size was found, so this seems safe enough. (And helps account
+ # for any bootarchives, fs overhead, etc.)
+ pd._cbytes_added *= 1.25
+ pd._bytes_added *= 1.25
+
+ # XXX For now, include cbytes_added in bytes_added total; in the
+ # future, this should only happen if they share the same
+ # filesystem.
+ pd._bytes_added += pd._cbytes_added
+ self.__update_avail_space()
+
def evaluate(self):
"""Given already determined fmri changes,
build pkg plans and figure out exact impact of
@@ -2541,63 +2817,23 @@
# plan is no longer valid.
raise api_errors.InvalidPlanError()
- self.evaluate_pkg_plans()
- self.merge_actions()
- self.compile_release_notes()
-
- fmri_updates = [
- (p.origin_fmri, p.destination_fmri)
- for p in self.pd.pkg_plans
- ]
- if not self.pd._li_pkg_updates and fmri_updates:
+ self.__evaluate_pkg_plans()
+ self.__merge_actions()
+ self.__compile_release_notes()
+
+ if not self.pd._li_pkg_updates and self.pd.pkg_plans:
# oops. the caller requested no package updates and
# we couldn't satisfy that request.
+ fmri_updates = [
+ (p.origin_fmri, p.destination_fmri)
+ for p in self.pd.pkg_plans
+ ]
raise api_errors.PlanCreationException(
pkg_updates_required=fmri_updates)
- for p in self.pd.pkg_plans:
- cpbytes, pbytes = p.get_bytes_added()
- if p.destination_fmri:
- mpath = self.image.get_manifest_path(
- p.destination_fmri)
- try:
- # Manifest data is essentially stored
- # three times (original, cache, catalog).
- # For now, include this in cbytes_added
- # since that's closest to where the
- # download cache is stored.
- self.pd._cbytes_added += \
- os.stat(mpath).st_size * 3
- except EnvironmentError, e:
- raise api_errors._convert_error(e)
- self.pd._cbytes_added += cpbytes
- self.pd._bytes_added += pbytes
-
- # Include state directory in cbytes_added for now since it's
- # closest to where the download cache is stored. (Twice the
- # amount is used because image state update involves using
- # a complete copy of existing state.)
- self.pd._cbytes_added += \
- misc.get_dir_size(self.image._statedir) * 2
-
- # Our slop factor is 25%; overestimating is safer than under-
- # estimating. This attempts to approximate how much overhead
- # the filesystem will impose on the operation. Empirical
- # testing suggests that overhead can vary wildly depending on
- # average file size, fragmentation, zfs metadata overhead, etc.
- # For an install of a package such as solaris-small-server into
- # an image, a 12% difference between actual size and installed
- # size was found, so this seems safe enough. (And helps account
- # for any bootarchives, fs overhead, etc.)
- self.pd._cbytes_added *= 1.25
- self.pd._bytes_added *= 1.25
-
- # XXX For now, include cbytes_added in bytes_added total; in the
- # future, this should only happen if they share the same
- # filesystem.
- self.pd._bytes_added += self.pd._cbytes_added
-
- self.__update_avail_space()
+ # These must be done after action merging.
+ self.__evaluate_pkg_preserved_files()
+ self.__evaluate_pkg_downloads()
def __update_avail_space(self):
"""Update amount of available space on FS"""
@@ -2650,7 +2886,7 @@
finally:
self.image.cleanup_downloads()
- def compile_release_notes(self):
+ def __compile_release_notes(self):
"""Figure out what release notes need to be displayed"""
release_notes = self.pd._actuators.get_release_note_info()
must_display = False
@@ -2671,7 +2907,7 @@
self.pd.release_notes = (must_display, notes)
- def save_release_notes(self):
+ def __save_release_notes(self):
"""Save a copy of the release notes and store the file name"""
if self.pd.release_notes[1]:
# create a file in imgdir/notes
@@ -2689,7 +2925,7 @@
tmpfile.close()
self.pd.release_notes_name = os.path.basename(path)
- def evaluate_pkg_plans(self):
+ def __evaluate_pkg_plans(self):
"""Internal helper function that does the work of converting
fmri changes into pkg plans."""
@@ -3124,7 +3360,7 @@
self.pd._new_mediators = prop_mediators
# Link mediation is complete.
- def merge_actions(self):
+ def __merge_actions(self):
"""Given a set of fmri changes and their associated pkg plan,
merge all the resultant actions for the packages being
updated."""
@@ -4055,7 +4291,7 @@
self.pd._actuators.exec_post_actuators(self.image)
self.image._create_fast_lookups(progtrack=self.__progtrack)
- self.save_release_notes()
+ self.__save_release_notes()
# success
self.pd.state = plandesc.EXECUTED_OK
--- a/src/tests/cli/t_pkg_install.py Mon Mar 24 10:12:12 2014 -0700
+++ b/src/tests/cli/t_pkg_install.py Wed Mar 26 10:39:37 2014 -0700
@@ -49,6 +49,31 @@
from pkg.client.pkgdefs import EXIT_OOPS
+class _TestHelper(object):
+ """Private helper class for shared functionality between test
+ classes."""
+
+ def _assertEditables(self, moved=[], removed=[], installed=[],
+ updated=[]):
+ """Private helper function that verifies that expected editables
+ are listed in parsable output. If no editable of a given type
+ is specified, then no editable files are expected."""
+
+ changed = []
+ if moved:
+ changed.append(['moved', moved])
+ if removed:
+ changed.append(['removed', removed])
+ if installed:
+ changed.append(['installed', installed])
+ if updated:
+ changed.append(['updated', updated])
+
+ self.assertEqualParsable(self.output,
+ include=["change-editables"],
+ change_editables=changed)
+
+
class TestPkgInstallBasics(pkg5unittest.SingleDepotTestCase):
# Only start/stop the depot once (instead of for every test)
persistent_setup = True
@@ -994,14 +1019,10 @@
their paths can be installed or exact-installed, updated, and
uninstalled."""
- self.install_fuzz_helper("install")
- self.install_fuzz_helper("exact-install")
-
- def install_fuzz_helper(self, install_cmd):
self.pkgsend_bulk(self.rurl, self.fuzzy)
self.image_create(self.rurl)
- self.pkg("%s fuzzy@1" % install_cmd)
+ self.pkg("install fuzzy@1")
self.pkg("verify -v")
self.pkg("update -vvv fuzzy@2")
self.pkg("verify -v")
@@ -2056,7 +2077,7 @@
self.pkg("verify -v")
-class TestPkgInstallUpgrade(pkg5unittest.SingleDepotTestCase):
+class TestPkgInstallUpgrade(_TestHelper, pkg5unittest.SingleDepotTestCase):
# Only start/stop the depot once (instead of for every test)
persistent_setup = True
@@ -2440,7 +2461,7 @@
add depend type=require [email protected]
close
open [email protected]
- add file tmp/preserve3 path=foo2 mode=0644 owner=root group=root original_name=orig_pkg:foo1 preserve=true
+ add file tmp/foo2 path=foo2 mode=0644 owner=root group=root original_name=orig_pkg:foo1 preserve=true
add file tmp/bronze1 path=bronze1 mode=0644 owner=root group=root preserve=true
close
"""
@@ -2495,7 +2516,7 @@
"tmp/gold-shadow", "tmp/gold-ftpusers", "tmp/gold-silly",
"tmp/silver-silly", "tmp/preserve1", "tmp/preserve2",
"tmp/preserve3", "tmp/renold1", "tmp/renold3", "tmp/rennew1",
- "tmp/rennew3", "tmp/liveroot1", "tmp/liveroot2",
+ "tmp/rennew3", "tmp/liveroot1", "tmp/liveroot2", "tmp/foo2",
]
misc_files2 = {
@@ -2707,10 +2728,7 @@
"""Test for editable files moving between packages or locations
or both."""
- self.upgrade3_helper("install")
- self.upgrade3_helper("exact-install")
-
- def upgrade3_helper(self, install_cmd):
+ install_cmd = "install"
self.pkgsend_bulk(self.rurl, (self.silver10, self.silver20,
self.silver30, self.gold10, self.gold20, self.gold30,
self.golduser10, self.golduser20, self.silveruser))
@@ -2718,7 +2736,15 @@
self.image_create(self.rurl)
# test 1: move an editable file between packages
- self.pkg("%s [email protected] [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected] [email protected]" % install_cmd)
+ self._assertEditables(
+ installed=[
+ 'etc/ftpd/ftpusers',
+ 'etc/group',
+ 'etc/passwd',
+ 'etc/shadow',
+ ]
+ )
self.pkg("verify -v")
# modify config file
@@ -2730,17 +2756,27 @@
self.file_contains(file_path, test_str)
# update packages
- self.pkg("%s [email protected] [email protected]" % install_cmd)
+ self.pkg("%s -nvv [email protected] [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected] [email protected]" % install_cmd)
+ self._assertEditables()
self.pkg("verify -v")
# make sure /etc/passwd contains still correct string
self.file_contains(file_path, test_str)
- self.pkg("uninstall silver gold")
+ self.pkg("uninstall --parsable=0 silver gold")
+ self._assertEditables(
+ removed=[
+ 'etc/ftpd/ftpusers',
+ 'etc/group',
+ 'etc/passwd',
+ 'etc/shadow',
+ ],
+ )
# test 2: change an editable file's path within a package
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected]" % install_cmd)
self.pkg("verify -v")
# modify config file
@@ -2748,19 +2784,30 @@
file_path = "etc/passwd"
self.file_append(file_path, test_str)
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected]" % install_cmd)
+ self._assertEditables(
+ moved=[['etc/passwd', 'etc/config2']],
+ removed=[
+ 'etc/ftpd/ftpusers',
+ 'etc/group',
+ 'etc/shadow',
+ ],
+ )
self.pkg("verify -v")
# make sure /etc/config2 contains correct string
file_path = "etc/config2"
self.file_contains(file_path, test_str)
- self.pkg("uninstall gold")
+ self.pkg("uninstall --parsable=0 gold")
+ self._assertEditables(
+ removed=['etc/config2'],
+ )
self.pkg("verify -v")
# test 3: move an editable file between packages and change its path
- self.pkg("%s [email protected] [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected] [email protected]" % install_cmd)
self.pkg("verify -v")
# modify config file
@@ -2770,19 +2817,27 @@
self.file_contains(file_path, test_str)
- self.pkg("%s [email protected] [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected] [email protected]" % install_cmd)
+ self._assertEditables(
+ moved=[['etc/passwd', 'etc/config2']],
+ removed=[
+ 'etc/ftpd/ftpusers',
+ 'etc/group',
+ 'etc/shadow',
+ ],
+ )
self.pkg("verify -v")
# make sure /etc/config2 now contains correct string
file_path = "etc/config2"
self.file_contains(file_path, test_str)
- self.pkg("uninstall gold silver")
+ self.pkg("uninstall --parsable=0 gold silver")
# test 4: move /etc/passwd between packages and ensure that we
# can still uninstall a user at the same time.
- self.pkg("%s [email protected] [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected] [email protected]" % install_cmd)
self.pkg("verify -v")
# add a user
@@ -2805,8 +2860,9 @@
silly_inode = os.stat(silly_path).st_ino
# update packages
- self.pkg("%s [email protected] [email protected] [email protected] silveruser"
- % install_cmd)
+ self.pkg("%s --parsable=0 [email protected] [email protected] [email protected] "
+ "silveruser" % install_cmd)
+ self._assertEditables()
# make sure Kermie is still installed and still has our local
# changes
@@ -2821,18 +2877,13 @@
"""Test to make sure hardlinks are correctly restored when file
they point to is updated."""
- self.upgrade4_helper("install")
- self.upgrade4_helper("exact-install")
-
- def upgrade4_helper(self, install_cmd):
self.pkgsend_bulk(self.rurl, (self.iron10, self.iron20))
-
- self.image_create(self.rurl)
-
- self.pkg("%s [email protected]" % install_cmd)
+ self.image_create(self.rurl)
+
+ self.pkg("install [email protected]")
self.pkg("verify -v")
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("install [email protected]")
self.pkg("verify -v")
def test_upgrade_liveroot(self):
@@ -2923,57 +2974,78 @@
"""Verify that file preserve=true works as expected during
package install, update, upgrade, and removal."""
- self.file_preserve("install")
- self.file_preserve("exact-install")
-
- def file_preserve(self, install_cmd):
+ install_cmd = "install"
self.pkgsend_bulk(self.rurl, (self.preserve1, self.preserve2,
self.preserve3, self.renpreserve))
self.image_create(self.rurl)
# If there are no local modifications, no preservation should be
# done. First with no content change ...
- self.pkg("%s preserve@1" % install_cmd)
- self.pkg("%s preserve@2" % install_cmd)
+ self.pkg("%s --parsable=0 preserve@1" % install_cmd)
+ self._assertEditables(
+ installed=['testme'],
+ )
+ self.pkg("%s --parsable=0 preserve@2" % install_cmd)
+ self._assertEditables(
+ updated=['testme'],
+ )
self.file_contains("testme", "preserve1")
self.pkg("verify preserve")
- self.pkg("update preserve@1")
+ self.pkg("update --parsable=0 preserve@1")
+ self._assertEditables(
+ updated=['testme'],
+ )
self.file_contains("testme", "preserve1")
self.pkg("verify preserve")
- self.pkg("uninstall preserve")
+ self.pkg("uninstall --parsable=0 preserve")
# ... and again with content change.
- self.pkg("install preserve@1")
- self.pkg("install preserve@3")
+ self.pkg("install --parsable=0 preserve@1")
+ self._assertEditables(
+ installed=['testme'],
+ )
+ self.pkg("install --parsable=0 preserve@3")
+ self._assertEditables(
+ updated=['testme'],
+ )
self.file_contains("testme", "preserve3")
- self.pkg("update preserve@1")
+ self.pkg("update --parsable=0 preserve@1")
+ self._assertEditables(
+ updated=['testme'],
+ )
+
self.file_contains("testme", "preserve1")
self.pkg("verify preserve")
- self.pkg("uninstall preserve")
+ self.pkg("uninstall --parsable=0 preserve")
# Modify the file locally and update to a version where the
# content changes.
- self.pkg("%s preserve@1" % install_cmd)
+ self.pkg("%s --parsable=0 preserve@1" % install_cmd)
self.file_append("testme", "junk")
self.file_contains("testme", "preserve1")
- self.pkg("%s preserve@3" % install_cmd)
+ self.pkg("%s --parsable=0 preserve@3" % install_cmd)
+ self._assertEditables()
self.file_contains("testme", "preserve1")
self.file_contains("testme", "junk")
self.file_doesnt_exist("testme.old")
self.file_doesnt_exist("testme.new")
self.pkg("verify preserve")
- self.pkg("uninstall preserve")
+ self.pkg("uninstall --parsable=0 preserve")
# Modify the file locally and downgrade to a version where
# the content changes.
- self.pkg("%s preserve@3" % install_cmd)
+ self.pkg("%s --parsable=0 preserve@3" % install_cmd)
self.file_append("testme", "junk")
self.file_contains("testme", "preserve3")
- self.pkg("update preserve@1")
+ self.pkg("update --parsable=0 preserve@1")
+ self._assertEditables(
+ moved=[['testme', 'testme.update']],
+ installed=['testme'],
+ )
self.file_doesnt_contain("testme", "preserve3")
self.file_doesnt_contain("testme", "junk")
self.file_doesnt_exist("testme.old")
@@ -2981,61 +3053,74 @@
self.file_exists("testme.update")
self.file_remove("testme.update")
self.pkg("verify preserve")
- self.pkg("uninstall preserve")
+ self.pkg("uninstall --parsable=0 preserve")
# Modify the file locally and update to a version where just the
# mode changes.
- self.pkg("%s preserve@1" % install_cmd)
+ self.pkg("%s --parsable=0 preserve@1" % install_cmd)
self.file_append("testme", "junk")
- self.pkg("%s preserve@2" % install_cmd)
+ self.pkg("%s --parsable=0 preserve@2" % install_cmd)
+ self._assertEditables(
+ updated=['testme'],
+ )
self.file_contains("testme", "preserve1")
self.file_contains("testme", "junk")
self.file_doesnt_exist("testme.old")
self.file_doesnt_exist("testme.new")
- self.pkg("update preserve@1")
+ self.pkg("update --parsable=0 preserve@1")
+ self._assertEditables(
+ updated=['testme'],
+ )
self.file_contains("testme", "preserve1")
self.file_contains("testme", "junk")
self.file_doesnt_exist("testme.old")
self.file_doesnt_exist("testme.new")
self.file_doesnt_exist("testme.update")
- self.pkg("%s preserve@2" % install_cmd)
+ self.pkg("%s --parsable=0 preserve@2" % install_cmd)
+ self._assertEditables(
+ updated=['testme'],
+ )
self.file_doesnt_exist("testme.old")
self.file_doesnt_exist("testme.new")
# Remove the file locally and update the package; this should
# simply replace the missing file.
self.file_remove("testme")
- self.pkg("%s preserve@3" % install_cmd)
+ self.pkg("%s --parsable=0 preserve@3" % install_cmd)
+ self._assertEditables(
+ installed=['testme'],
+ )
self.pkg("verify preserve")
self.file_exists("testme")
# Remove the file locally and downgrade the package; this should
# simply replace the missing file.
self.file_remove("testme")
- self.pkg("update preserve@2")
+ self.pkg("update --parsable=0 preserve@2")
+ self._assertEditables(
+ installed=['testme'],
+ )
self.pkg("verify preserve")
self.file_exists("testme")
self.pkg("uninstall preserve@2")
- # Preserved files don't get their mode changed, and verify will
- # still balk, so fix up the mode.
- self.pkg("%s preserve@1" % install_cmd)
- self.pkg("%s preserve@2" % install_cmd)
- self.file_chmod("testme", 0640)
+ # Verify preserved files will have their mode changed on update.
+ self.pkg("%s --parsable=0 preserve@1" % install_cmd)
+ self.pkg("%s --parsable=0 preserve@2" % install_cmd)
self.pkg("verify preserve")
# Verify that a package with a missing file that is marked with
# the preserve=true won't cause uninstall failure.
self.file_remove("testme")
self.file_doesnt_exist("testme")
- self.pkg("uninstall preserve")
+ self.pkg("uninstall --parsable=0 preserve")
# Verify preserve works across package rename with and without
# original_name use and even when the original file is missing.
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected]" % install_cmd)
foo1_path = os.path.join(self.get_img_path(), "foo1")
self.assert_(os.path.isfile(foo1_path))
bronze1_path = os.path.join(self.get_img_path(), "bronze1")
@@ -3044,39 +3129,53 @@
# Update across the rename boundary, then verify that the files
# were installed with their new name and the old ones were
# removed.
- self.pkg("update orig_pkg")
+ self.pkg("update -nvv orig_pkg")
+ self.pkg("update --parsable=0 orig_pkg")
+ self._assertEditables(
+ moved=[['foo1', 'foo2']],
+ )
+
foo2_path = os.path.join(self.get_img_path(), "foo2")
self.assert_(not os.path.exists(foo1_path))
self.assert_(os.path.isfile(foo2_path))
self.assert_(os.path.isfile(bronze1_path))
- self.pkg("uninstall \*")
+ self.pkg("uninstall --parsable=0 \*")
# Update across the rename boundary, then truncate each of the
# preserved files. They should remain empty even though one is
# changing names and the other is simply being preserved across
# a package rename.
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected]" % install_cmd)
open(foo1_path, "wb").close()
open(bronze1_path, "wb").close()
- self.pkg("update orig_pkg")
+ self.pkg("update --parsable=0 orig_pkg")
+ self._assertEditables(
+ moved=[['foo1', 'foo2']],
+ )
self.assert_(not os.path.exists(foo1_path))
self.assert_(os.path.isfile(foo2_path))
self.assertEqual(os.stat(foo2_path).st_size, 0)
self.assert_(os.path.isfile(bronze1_path))
self.assertEqual(os.stat(bronze1_path).st_size, 0)
- self.pkg("uninstall \*")
+ self.pkg("uninstall --parsable=0 \*")
+ self._assertEditables(
+ removed=['bronze1', 'foo2'],
+ )
# Update across the rename boundary, then verify that a change
# in file name will cause re-delivery of preserved files, but
# unchanged, preserved files will not be re-delivered.
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected]" % install_cmd)
os.unlink(foo1_path)
os.unlink(bronze1_path)
- self.pkg("update orig_pkg")
+ self.pkg("update --parsable=0 orig_pkg")
+ self._assertEditables(
+ moved=[['foo1', 'foo2']],
+ )
self.assert_(not os.path.exists(foo1_path))
self.assert_(os.path.isfile(foo2_path))
self.assert_(not os.path.exists(bronze1_path))
- self.pkg("uninstall \*")
+ self.pkg("uninstall --parsable=0 \*")
# Ensure directory is empty before testing.
api_inst = self.get_img_api_obj()
@@ -3086,9 +3185,9 @@
# Verify that unmodified, preserved files will not be salvaged
# on uninstall.
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected]" % install_cmd)
self.file_contains("testme", "preserve1")
- self.pkg("uninstall preserve")
+ self.pkg("uninstall --parsable=0 preserve")
salvaged = [
n for n in os.listdir(sroot)
if n.startswith("testme-")
@@ -3097,19 +3196,16 @@
# Verify that modified, preserved files will be salvaged
# on uninstall.
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected]" % install_cmd)
self.file_contains("testme", "preserve1")
self.file_append("testme", "junk")
- self.pkg("uninstall preserve")
+ self.pkg("uninstall --parsable=0 preserve")
self.__salvage_file_contains(sroot, "testme", "junk")
def test_file_preserve_renameold(self):
"""Make sure that file upgrade with preserve=renameold works."""
- self.file_preserve_renameold_helper("install")
- self.file_preserve_renameold_helper("exact-install")
-
- def file_preserve_renameold_helper(self, install_cmd):
+ install_cmd = "install"
plist = self.pkgsend_bulk(self.rurl, (self.renameold1,
self.renameold2, self.renameold3))
self.image_create(self.rurl)
@@ -3137,7 +3233,11 @@
# content changes.
self.pkg("%s renold@1" % install_cmd)
self.file_append("testme", "junk")
- self.pkg("%s renold@3" % install_cmd)
+ self.pkg("%s --parsable=0 renold@3" % install_cmd)
+ self._assertEditables(
+ moved=[['testme', 'testme.old']],
+ installed=['testme'],
+ )
self.file_contains("testme.old", "junk")
self.file_doesnt_contain("testme", "junk")
self.file_contains("testme", "renold3")
@@ -3150,7 +3250,11 @@
# mode changes.
self.pkg("%s renold@1" % install_cmd)
self.file_append("testme", "junk")
- self.pkg("%s renold@2" % install_cmd)
+ self.pkg("%s --parsable=0 renold@2" % install_cmd)
+ self._assertEditables(
+ moved=[['testme', 'testme.old']],
+ installed=['testme'],
+ )
self.file_contains("testme.old", "junk")
self.file_doesnt_contain("testme", "junk")
self.file_contains("testme", "renold1")
@@ -3162,17 +3266,17 @@
# simply replace the missing file.
self.pkg("%s renold@1" % install_cmd)
self.file_remove("testme")
- self.pkg("%s renold@2" % install_cmd)
+ self.pkg("%s --parsable=0 renold@2" % install_cmd)
+ self._assertEditables(
+ installed=['testme'],
+ )
self.pkg("verify renold")
self.pkg("uninstall renold")
def test_file_preserve_renamenew(self):
"""Make sure that file ugprade with preserve=renamenew works."""
- self.file_preserve_renamenew_helper("install")
- self.file_preserve_renamenew_helper("exact-install")
-
- def file_preserve_renamenew_helper(self, install_cmd):
+ install_cmd = "install"
plist = self.pkgsend_bulk(self.rurl, (self.renamenew1,
self.renamenew2, self.renamenew3))
self.image_create(self.rurl)
@@ -3180,7 +3284,10 @@
# If there are no local modifications, no preservation should be
# done. First with no content change ...
self.pkg("%s rennew@1" % install_cmd)
- self.pkg("%s rennew@2" % install_cmd)
+ self.pkg("%s --parsable=0 rennew@2" % install_cmd)
+ self._assertEditables(
+ updated=['testme'],
+ )
self.file_contains("testme", "rennew1")
self.file_doesnt_exist("testme.new")
self.file_doesnt_exist("testme.old")
@@ -3189,7 +3296,10 @@
# ... and again with content change
self.pkg("%s rennew@1" % install_cmd)
- self.pkg("%s rennew@3" % install_cmd)
+ self.pkg("%s --parsable=0 rennew@3" % install_cmd)
+ self._assertEditables(
+ updated=['testme'],
+ )
self.file_contains("testme", "rennew3")
self.file_doesnt_exist("testme.new")
self.file_doesnt_exist("testme.old")
@@ -3200,7 +3310,10 @@
# content changes.
self.pkg("%s rennew@1" % install_cmd)
self.file_append("testme", "junk")
- self.pkg("%s rennew@3" % install_cmd)
+ self.pkg("%s --parsable=0 rennew@3" % install_cmd)
+ self._assertEditables(
+ installed=['testme.new'],
+ )
self.file_contains("testme", "junk")
self.file_doesnt_contain("testme.new", "junk")
self.file_contains("testme.new", "rennew3")
@@ -3214,14 +3327,19 @@
# mode changes.
self.pkg("%s rennew@1" % install_cmd)
self.file_append("testme", "junk")
- self.pkg("%s rennew@2" % install_cmd)
+ self.pkg("%s --parsable=0 rennew@2" % install_cmd)
+ self._assertEditables(
+ installed=['testme.new'],
+ )
self.file_contains("testme", "junk")
self.file_doesnt_contain("testme.new", "junk")
self.file_contains("testme.new", "rennew1")
self.file_doesnt_exist("testme.old")
- # Preserved files don't get their mode changed, and verify will
- # still balk, so fix up the mode.
+ # The original file won't be touched on update, so verify fails.
+ self.pkg("verify rennew", exit=1)
+
+ # Ensure that after fixing mode, verify passes.
self.file_chmod("testme", 0640)
self.pkg("verify rennew")
self.pkg("uninstall rennew")
@@ -3231,7 +3349,10 @@
# simply replace the missing file.
self.pkg("%s rennew@1" % install_cmd)
self.file_remove("testme")
- self.pkg("%s rennew@2" % install_cmd)
+ self.pkg("%s --parsable=0 rennew@2" % install_cmd)
+ self._assertEditables(
+ installed=['testme'],
+ )
self.file_doesnt_exist("testme.new")
self.file_doesnt_exist("testme.old")
self.pkg("verify rennew")
@@ -3240,10 +3361,7 @@
def test_file_preserve_legacy(self):
"""Verify that preserve=legacy works as expected."""
- self.file_preserve_legacy_helper("install")
- self.file_preserve_legacy_helper("exact-install")
-
- def file_preserve_legacy_helper(self, install_cmd):
+ install_cmd = "install"
self.pkgsend_bulk(self.rurl, (self.preslegacy,
self.renpreslegacy))
self.image_create(self.rurl)
@@ -3258,7 +3376,10 @@
# install if a package being installed delivers the same file
# and that the new file will be installed.
self.file_append("testme", "unpackaged")
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected]" % install_cmd)
+ self._assertEditables(
+ installed=['testme'],
+ )
self.file_contains("testme", "preserve1")
self.__salvage_file_contains(sroot, "testme", "unpackaged")
shutil.rmtree(sroot)
@@ -3266,14 +3387,21 @@
# Verify that a package transitioning to preserve=legacy from
# some other state will have the existing file renamed using
# .legacy as an extension.
- self.pkg("update [email protected]")
+ self.pkg("update --parsable=0 [email protected]")
+ self._assertEditables(
+ moved=[['testme', 'testme.legacy']],
+ installed=['testme'],
+ )
self.file_contains("testme.legacy", "preserve1")
self.file_contains("testme", "preserve2")
# Verify that if an action with preserve=legacy is upgraded
# and its payload changes that the new payload is delivered
# but the old .legacy file is not modified.
- self.pkg("update [email protected]")
+ self.pkg("update --parsable=0 [email protected]")
+ self._assertEditables(
+ updated=['testme'],
+ )
self.file_contains("testme.legacy", "preserve1")
self.file_contains("testme", "preserve3")
@@ -3291,37 +3419,47 @@
# Verify that an initial install of an action with
# preserve=legacy will not install the payload of the action.
self.pkg("uninstall preslegacy")
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected]" % install_cmd)
+ self._assertEditables()
self.file_doesnt_exist("testme")
# Verify that if the original preserved file is missing during
# a transition to preserve=legacy from some other state that
# the new action is still delivered and the operation succeeds.
self.pkg("uninstall preslegacy")
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected]" % install_cmd)
+ self._assertEditables(
+ installed=['testme'],
+ )
self.file_remove("testme")
- self.pkg("update")
+ self.pkg("update --parsable=0")
+ self._assertEditables(
+ installed=['testme'],
+ )
self.file_contains("testme", "preserve3")
# Verify that a preserved file can be moved from one package to
# another and transition to preserve=legacy at the same time.
self.pkg("uninstall preslegacy")
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("%s --parsable=0 [email protected]" % install_cmd)
+ self._assertEditables(
+ installed=['testme'],
+ )
self.file_exists("testme")
- self.pkg("update")
+ self.pkg("update --parsable=0")
+ self._assertEditables(
+ moved=[['testme', 'newme.legacy']],
+ installed=['newme'],
+ )
self.file_contains("testme.legacy", "preserve1")
self.file_contains("newme", "preserve2")
def test_directory_salvage(self):
"""Make sure basic directory salvage works as expected"""
- self.directory_salvage_helper("install")
- self.directory_salvage_helper("exact-install")
-
- def directory_salvage_helper(self, install_cmd):
self.pkgsend_bulk(self.rurl, self.salvage)
self.image_create(self.rurl)
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("install [email protected]")
self.file_append("var/mail/foo", "foo's mail")
self.file_append("var/mail/bar", "bar's mail")
self.file_append("var/mail/baz", "baz's mail")
@@ -3334,16 +3472,12 @@
"""Make sure directory salvage works as expected when salvaging
content to an existing packaged directory."""
- self.directory_salvage_persistent_helper("install")
- self.directory_salvage_persistent_helper("exact-install")
-
- def directory_salvage_persistent_helper(self, install_cmd):
# we salvage content from two directories,
# var/noodles and var/spaghetti each of which disappear over
# subsequent updates.
self.pkgsend_bulk(self.rurl, self.salvage)
self.image_create(self.rurl)
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("install [email protected]")
self.file_append("var/mail/foo", "foo's mail")
self.file_append("var/noodles/noodles.txt", "yum")
self.pkg("update [email protected]")
@@ -3356,7 +3490,7 @@
# ensure that we can jump from 1.0 to 3.0 directly.
self.image_create(self.rurl)
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("install [email protected]")
self.file_append("var/noodles/noodles.txt", "yum")
self.pkg("update [email protected]")
self.file_exists("var/persistent/noodles.txt")
@@ -3365,14 +3499,10 @@
"""Make sure salvaging directories with special files works as
expected."""
- self.special_salvage_helper("install")
- self.special_salvage_helper("exact-install")
-
- def special_salvage_helper(self, install_cmd):
self.pkgsend_bulk(self.rurl, self.salvage_special)
self.image_create(self.rurl, destroy=True, fs=("var",))
- self.pkg("%s salvage-special" % install_cmd)
+ self.pkg("install salvage-special")
os.mkfifo(os.path.join(self.img_path(), "salvage", "fifo"))
sock = socket.socket(socket.AF_UNIX)
@@ -3416,15 +3546,11 @@
"""Ensure that files transitioning to a link still follow
original_name preservation rules."""
- self.link_preserve_helper("install")
- self.link_preserve_helper("exact-install")
-
- def link_preserve_helper(self, install_cmd):
self.pkgsend_bulk(self.rurl, (self.linkpreserve))
self.image_create(self.rurl, destroy=True, fs=("var",))
# Install package with original config file location.
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("install --parsable=0 [email protected]")
cfg_path = os.path.join("etc", "ssh", "sshd_config")
abs_path = os.path.join(self.get_img_path(), cfg_path)
@@ -3437,19 +3563,25 @@
# Install new package version, verify file replaced with link
# and modified version was moved to new location.
new_cfg_path = os.path.join("etc", "sunssh", "sshd_config")
- self.pkg("update [email protected]")
+ self.pkg("update --parsable=0 [email protected]")
+ self._assertEditables(
+ moved=[['etc/ssh/sshd_config', 'etc/sunssh/sshd_config']]
+ )
self.assert_(os.path.islink(abs_path))
self.file_exists(new_cfg_path)
self.file_contains(new_cfg_path, "modified")
# Uninstall, then install original version again.
self.pkg("uninstall linkpreserve")
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("install [email protected]")
self.file_contains(cfg_path, "preserve1")
# Install new package version and verify that unmodified file is
# replaced with new configuration file.
- self.pkg("update [email protected]")
+ self.pkg("update --parsable=0 [email protected]")
+ self._assertEditables(
+ moved=[['etc/ssh/sshd_config', 'etc/sunssh/sshd_config']]
+ )
self.file_contains(new_cfg_path, "preserve2")
def test_many_hashalgs(self):
@@ -3457,13 +3589,9 @@
contains more hash attributes than the old action, that the
upgrade works."""
- self.many_hashalgs_helper("install")
- self.many_hashalgs_helper("exact-install")
-
- def many_hashalgs_helper(self, install_cmd):
self.pkgsend_bulk(self.rurl, (self.iron10))
self.image_create(self.rurl, destroy=True)
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("install [email protected]")
self.pkg("contents -m iron")
# We have not enabled SHA2 hash publication yet.
self.assert_("pkg.hash.sha256" not in self.output)
@@ -3479,7 +3607,7 @@
# This also tests package retrieval: we always retrieve packages
# with the least-preferred hash, but verify with the
# most-preferred hash.
- self.pkg("%s [email protected]" % install_cmd)
+ self.pkg("install [email protected]")
self.pkg("contents -m iron")
self.assert_("pkg.hash.sha256" in self.output)
@@ -4032,79 +4160,6 @@
self.assert_("gonzo\n" not in file(fpath).readlines())
self.pkg("verify ftpuserimp")
- def test_ftpuser_exact_install(self):
- """Make sure we correctly handle /etc/ftpd/ftpusers."""
-
- notftpuser = """
- open notftpuser@1
- add user username=animal group=root ftpuser=false
- add depend fmri=pkg:/[email protected] type=require
- close"""
-
- ftpuserexp = """
- open ftpuserexp@1
- add user username=fozzie group=root ftpuser=true
- add depend fmri=pkg:/[email protected] type=require
- close"""
-
- ftpuserimp = """
- open ftpuserimp@1
- add user username=gonzo group=root
- add depend fmri=pkg:/[email protected] type=require
- close"""
-
- self.pkgsend_bulk(self.rurl, (self.basics0, notftpuser,
- ftpuserexp, ftpuserimp))
- self.image_create(self.rurl)
-
- self.pkg("install basics")
-
- # Add a user with ftpuser=false. Make sure the user is added to
- # the file, and that the user verifies.
- self.pkg("exact-install notftpuser")
- fpath = self.get_img_path() + "/etc/ftpd/ftpusers"
- self.assert_("animal\n" in file(fpath).readlines())
- self.pkg("verify notftpuser")
-
- # Put a user into the ftpusers file as shipped, then add that
- # user, with ftpuser=false. Make sure the user remains in the
- # file, and that the user verifies.
- self.pkg("uninstall notftpuser")
- file(fpath, "a").write("animal\n")
- self.pkg("exact-install notftpuser")
- self.assert_("animal\n" in file(fpath).readlines())
- self.pkg("verify notftpuser")
-
- # Add a user with an explicit ftpuser=true. Make sure the user
- # is not added to the file, and that the user verifies.
- self.pkg("exact-install ftpuserexp")
- self.assert_("fozzie\n" not in file(fpath).readlines())
- self.pkg("verify ftpuserexp")
-
- # Put a user into the ftpusers file as shipped, then add that
- # user, with an explicit ftpuser=true. Make sure the user is
- # stripped from the file, and that the user verifies.
- self.pkg("uninstall ftpuserexp")
- file(fpath, "a").write("fozzie\n")
- self.pkg("exact-install ftpuserexp")
- self.assert_("fozzie\n" not in file(fpath).readlines())
- self.pkg("verify ftpuserexp")
-
- # Add a user with an implicit ftpuser=true. Make sure the user
- # is not added to the file, and that the user verifies.
- self.pkg("exact-install ftpuserimp")
- self.assert_("gonzo\n" not in file(fpath).readlines())
- self.pkg("verify ftpuserimp")
-
- # Put a user into the ftpusers file as shipped, then add that
- # user, with an implicit ftpuser=true. Make sure the user is
- # stripped from the file, and that the user verifies.
- self.pkg("uninstall ftpuserimp")
- file(fpath, "a").write("gonzo\n")
- self.pkg("exact-install ftpuserimp")
- self.assert_("gonzo\n" not in file(fpath).readlines())
- self.pkg("verify ftpuserimp")
-
def test_groupverify_install(self):
"""Make sure we correctly verify group actions when users have
been added."""
@@ -4142,45 +4197,6 @@
gdata = file(gpath).readlines()
self.assert_(gdata[-1].find("muppets2") == 0)
- def test_groupverify_exact_install(self):
- """Make sure we correctly verify group actions when users have
- been added."""
-
- simplegroups = """
- open simplegroup@1
- add group groupname=muppets gid=100
- add depend fmri=pkg:/[email protected] type=require
- close
- open simplegroup2@1
- add group groupname=muppets2 gid=101
- add depend fmri=pkg:/[email protected] type=require
- close"""
-
- self.pkgsend_bulk(self.rurl, (self.basics0, simplegroups))
- self.image_create(self.rurl)
-
- self.pkg("install basics")
- self.pkg("exact-install simplegroup")
- self.pkg("verify simplegroup")
-
- # add additional members to group & verify
- gpath = self.get_img_file_path("etc/group")
- gdata = file(gpath).readlines()
- gdata[-1] = gdata[-1].rstrip() + "kermit,misspiggy\n"
- file(gpath, "w").writelines(gdata)
- self.pkg("verify simplegroup")
- self.pkg("uninstall simplegroup")
-
- # verify that groups appear in gid order.
- self.pkg("exact-install simplegroup simplegroup2")
- self.pkg("verify")
- gdata = file(gpath).readlines()
- self.assert_(gdata[-1].find("muppets2") == 0)
- self.pkg("uninstall simple*")
- self.pkg("exact-install simplegroup2 simplegroup")
- gdata = file(gpath).readlines()
- self.assert_(gdata[-1].find("muppets2") == 0)
-
def test_preexisting_group_install(self):
"""Make sure we correct any errors in pre-existing group actions"""
simplegroup = """
@@ -4212,39 +4228,6 @@
self.pkg("update simplegroup")
self.pkg("verify simplegroup")
- def test_preexisting_group_exact_install(self):
- """Make sure we correct any errors in pre-existing group actions"""
- simplegroup = """
- open simplegroup@1
- add group groupname=muppets gid=70
- add depend fmri=pkg:/[email protected] type=require
- close
- open simplegroup@2
- add dir path=/etc/muppet owner=root group=muppets mode=755
- add group groupname=muppets gid=70
- add depend fmri=pkg:/[email protected] type=require
- close"""
-
- self.pkgsend_bulk(self.rurl, (self.basics0, simplegroup))
- self.image_create(self.rurl)
-
- self.pkg("install basics")
- gpath = self.get_img_file_path("etc/group")
- gdata = file(gpath).readlines()
- gdata = ["muppets::1010:\n"] + gdata
- file(gpath, "w").writelines(gdata)
- self.pkg("verify")
- self.pkg("exact-install simplegroup@1")
- self.pkg("verify simplegroup")
- # check # lines beginning w/ 'muppets' in group file
- gdata = file(gpath).readlines()
- self.assert_(
- len([a for a in gdata if a.find("muppets") == 0]) == 1)
-
- # make sure we can add new version of same package
- self.pkg("update simplegroup")
- self.pkg("verify simplegroup")
-
def test_missing_ownergroup_install(self):
"""test what happens when a owner or group is missing"""
missing = """
@@ -4303,69 +4286,6 @@
self.pkg("install missing_owner@1")
self.pkg("verify muppetsgroup muppetsuser missing*")
- def test_missing_ownergroup_exact_install(self):
- """Test what happens when a owner or group is missing."""
-
- missing = """
- open missing_group@1
- add dir path=etc/muppet1 owner=root group=muppets mode=755
- add depend fmri=pkg:/[email protected] type=require
- close
- open missing_owner@1
- add dir path=etc/muppet2 owner=muppets group=root mode=755
- add depend fmri=pkg:/[email protected] type=require
- close
- open muppetsuser@1
- add user username=muppets group=bozomuppets uid=777
- add depend fmri=pkg:/[email protected] type=require
- close
- open muppetsuser@2
- add user username=muppets group=muppets uid=777
- add depend fmri=pkg:/[email protected] type=require
- add depend fmri=pkg:/muppetsgroup@1 type=require
- close
- open muppetsgroup@1
- add group groupname=muppets gid=777
- close
- """
-
- self.pkgsend_bulk(self.rurl, (self.basics0, missing))
- self.image_create(self.rurl)
- self.pkg("install basics")
-
- # try exact-installing directory w/ a non-existing group
- self.pkg("exact-install missing_group@1", exit=1)
- # try exact-installing directory w/ a non-existing owner
- self.pkg("exact-install missing_owner@1", exit=1)
- # try exact-installing user w/ unknown group
- self.pkg("exact-install muppetsuser@1", exit=1)
-
- # install group
- self.pkg("install muppetsgroup")
- # install working user & see if it all works.
- self.pkg("install muppetsuser@2")
- self.pkg("exact-install muppetsgroup missing_group@1")
- self.pkg("exact-install muppetsuser@2 missing_owner@1")
- self.pkg("verify")
- # edit group file to remove muppets group
- gpath = self.get_img_file_path("etc/group")
- gdata = file(gpath).readlines()
- file(gpath, "w").writelines(gdata[0:-1])
- # verify that we catch missing group
- # in both group and user actions
- self.pkg("verify muppetsgroup", 1)
- self.pkg("verify muppetsuser", 1)
- self.pkg("fix muppetsgroup", 0)
- self.pkg("verify muppetsgroup muppetsuser missing*")
- self.pkg("uninstall missing*")
- # try installing w/ broken group
- file(gpath, "w").writelines(gdata[0:-1])
- self.pkg("exact-install missing_group@1", 1)
- self.pkg("fix muppetsgroup")
- self.pkg("exact-install muppetsgroup missing_group@1")
- self.pkg("exact-install muppetsuser@2 missing_owner@1")
- self.pkg("verify muppetsgroup muppetsuser missing*")
-
def test_userverify_install(self):
"""Make sure we correctly verify user actions when the on-disk
databases have been modified."""
@@ -4524,167 +4444,6 @@
pdata = file(ppath).readlines()
pdata[-1].index("kermit")
- def test_userverify_exact_install(self):
- """Make sure we correctly verify user actions when the on-disk
- databases have been modified."""
-
- simpleusers = """
- open simpleuser@1
- add user username=misspiggy group=root gcos-field="& loves Kermie" login-shell=/bin/sh uid=5
- add depend fmri=pkg:/[email protected] type=require
- close
- open simpleuser2@1
- add user username=kermit group=root gcos-field="& loves mspiggy" login-shell=/bin/sh password=UP uid=6
- add depend fmri=pkg:/[email protected] type=require
- close
- open simpleuser2@2
- add user username=kermit group=root gcos-field="& loves mspiggy" login-shell=/bin/sh uid=6
- add depend fmri=pkg:/[email protected] type=require
- close"""
-
-
- self.pkgsend_bulk(self.rurl, (self.basics0, simpleusers))
- self.image_create(self.rurl)
-
- self.pkg("install basics")
- self.pkg("exact-install simpleuser")
- self.pkg("verify simpleuser")
-
- ppath = self.get_img_path() + "/etc/passwd"
- pdata = file(ppath).readlines()
- spath = self.get_img_path() + "/etc/shadow"
- sdata = file(spath).readlines()
-
- def finderr(err):
- self.assert_("\t\t" + err in self.output)
-
- # change a provided, empty-default field to something else
- pdata[-1] = "misspiggy:x:5:0:& loves Kermie:/:/bin/zsh"
- file(ppath, "w").writelines(pdata)
- self.pkg("verify simpleuser", exit=1)
- finderr("login-shell: '/bin/zsh' should be '/bin/sh'")
- self.pkg("fix simpleuser")
- self.pkg("verify simpleuser")
-
- # change a provided, non-empty-default field to the default
- pdata[-1] = "misspiggy:x:5:0:& User:/:/bin/sh"
- file(ppath, "w").writelines(pdata)
- self.pkg("verify simpleuser", exit=1)
- finderr("gcos-field: '& User' should be '& loves Kermie'")
- self.pkg("fix simpleuser")
- self.pkg("verify simpleuser")
-
- # change a non-provided, non-empty-default field to something
- # other than the default
- pdata[-1] = "misspiggy:x:5:0:& loves Kermie:/misspiggy:/bin/sh"
- file(ppath, "w").writelines(pdata)
- self.pkg("verify simpleuser", exit=1)
- finderr("home-dir: '/misspiggy' should be '/'")
- self.pkg("fix simpleuser")
- self.pkg("verify simpleuser")
-
- # add a non-provided, empty-default field
- pdata[-1] = "misspiggy:x:5:0:& loves Kermie:/:/bin/sh"
- sdata[-1] = "misspiggy:*LK*:14579:7:::::"
- file(ppath, "w").writelines(pdata)
- os.chmod(spath,
- stat.S_IMODE(os.stat(spath).st_mode)|stat.S_IWUSR)
- file(spath, "w").writelines(sdata)
- self.pkg("verify simpleuser", exit=1)
- finderr("min: '7' should be '<empty>'")
- # fails fix since we don't repair shadow entries on purpose
- self.pkg("fix simpleuser")
- self.pkg("verify simpleuser", exit=1)
- finderr("min: '7' should be '<empty>'")
-
- # remove a non-provided, non-empty-default field
- pdata[-1] = "misspiggy:x:5:0:& loves Kermie::/bin/sh"
- sdata[-1] = "misspiggy:*LK*:14579::::::"
- file(ppath, "w").writelines(pdata)
- file(spath, "w").writelines(sdata)
- self.pkg("verify simpleuser", exit=1)
- finderr("home-dir: '' should be '/'")
- self.pkg("fix simpleuser")
- self.pkg("verify simpleuser")
-
- # remove a provided, non-empty-default field
- pdata[-1] = "misspiggy:x:5:0::/:/bin/sh"
- file(ppath, "w").writelines(pdata)
- self.pkg("verify simpleuser", exit=1)
- finderr("gcos-field: '' should be '& loves Kermie'")
- self.pkg("fix simpleuser")
- self.pkg("verify simpleuser")
-
- # remove a provided, empty-default field
- pdata[-1] = "misspiggy:x:5:0:& loves Kermie:/:"
- file(ppath, "w").writelines(pdata)
- self.pkg("verify simpleuser", exit=1)
- finderr("login-shell: '' should be '/bin/sh'")
- self.pkg("fix simpleuser")
- self.pkg("verify simpleuser")
-
- # remove the user from /etc/passwd
- pdata[-1] = "misswiggy:x:5:0:& loves Kermie:/:"
- file(ppath, "w").writelines(pdata)
- self.pkg("verify simpleuser", exit=1)
- finderr("login-shell: '<missing>' should be '/bin/sh'")
- finderr("gcos-field: '<missing>' should be '& loves Kermie'")
- finderr("group: '<missing>' should be 'root'")
- self.pkg("fix simpleuser")
- self.pkg("verify simpleuser")
-
- # remove the user completely
- pdata[-1] = "misswiggy:x:5:0:& loves Kermie:/:"
- sdata[-1] = "misswiggy:*LK*:14579::::::"
- file(ppath, "w").writelines(pdata)
- file(spath, "w").writelines(sdata)
- self.pkg("verify simpleuser", exit=1)
- finderr("username: '<missing>' should be 'misspiggy'")
- self.pkg("fix simpleuser")
- self.pkg("verify simpleuser")
-
- # change the password and show an error
- self.pkg("verify simpleuser")
- sdata[-1] = "misspiggy:NP:14579::::::"
- file(spath, "w").writelines(sdata)
- self.pkg("verify simpleuser", exit=1)
- finderr("password: 'NP' should be '*LK*'")
- self.pkg("fix simpleuser")
- self.pkg("verify simpleuser")
-
- # verify that passwords set to anything
- # other than '*LK*" or 'NP' in manifest
- # do not cause verify errors if changed.
- self.pkg("exact-install --reject simpleuser simpleuser2@1")
- self.pkg("verify simpleuser2")
- pdata = file(ppath).readlines()
- sdata = file(spath).readlines()
- sdata[-1] = "kermit:$5$pWPEsjm2$GXjBRTjGeeWmJ81ytw3q1ah7QTaI7yJeRYZeyvB.Rp1:14579::::::"
- file(spath, "w").writelines(sdata)
- self.pkg("verify simpleuser2")
-
- # verify that upgrading package to version that implicitly
- # uses *LK* default causes password to change and that it
- # verifies correctly
- self.pkg("update simpleuser2@2")
- self.pkg("verify simpleuser2")
- sdata = file(spath).readlines()
- sdata[-1].index("*LK*")
-
- # ascertain that users are added in uid order when
- # installed at the same time.
- self.pkg("uninstall simpleuser2")
- self.pkg("exact-install simpleuser simpleuser2")
-
- pdata = file(ppath).readlines()
- pdata[-1].index("kermit")
-
- self.pkg("uninstall simpleuser simpleuser2")
- self.pkg("exact-install simpleuser2 simpleuser")
-
- pdata = file(ppath).readlines()
- pdata[-1].index("kermit")
-
def test_minugid(self):
"""Ensure that an unspecified uid/gid results in the first
unused."""
@@ -8356,7 +8115,7 @@
self.pkg("update", exit=1)
-class TestConflictingActions(pkg5unittest.SingleDepotTestCase):
+class TestConflictingActions(_TestHelper, pkg5unittest.SingleDepotTestCase):
"""This set of tests verifies that packages which deliver conflicting
actions into the same name in a namespace cannot be installed
simultaneously."""
@@ -9188,119 +8947,6 @@
self.pkg("uninstall pkg2", exit=1)
self.pkg("verify pkg2")
- def test_multiple_files_exact_install(self):
- """Test the behavior of pkg(1) when multiple file actions
- deliver to the same pathname."""
-
- self.image_create(self.rurl)
-
- # Duplicate files in the same package.
- self.pkg("exact-install dupfiles", exit=1)
-
- # Duplicate files in different packages, but in the same
- # transaction.
- self.pkg("exact-install dupfilesp1 dupfilesp2@0", exit=1)
-
- # Duplicate files in different packages, in different
- # transactions. This should succeed because exact-install will
- # uninstall dupfilesp1 first.
- self.pkg("exact-install dupfilesp1")
- self.pkg("exact-install dupfilesp2@0")
-
- # Test that being in a duplicate file situation doesn't break
- # you completely and allows you to add and remove other
- # packages.
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupfilesp1 dupfilesp2@0")
- self.pkg("exact-install implicitdirs2")
- self.pkg("uninstall implicitdirs2")
-
- # If the packages involved get upgraded by exact-install, that
- # means the old actions has been removed. So we should be okay.
- self.pkg("exact-install dupfilesp2 dupfilesp3")
- self.pkg("verify")
-
- # Test that removing one of two offending actions reverts the
- # system to a clean state.
- self.pkg("uninstall dupfilesp3")
- self.pkg("verify")
-
- # You should be able to upgrade to a fixed set of packages in
- # order to move past the problem, too.
- self.pkg("uninstall dupfilesp2")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupfilesp2@0")
- self.pkg("update")
- self.pkg("verify")
-
- # If we upgrade to a version of a conflicting package that no
- # longer has the conflict, amd at the same time introduce a new
- # file action at the path with different contents, we should
- # succeed with exact-install.
- self.pkg("uninstall dupfilesp2")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupfilesp2@0")
- self.pkg("exact-install dupfilesp2 dupfilesp4")
-
- # Removing one of more than two offending actions can't do much
- # of anything, but should leave the system alone.
- self.pkg("uninstall '*'")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupfilesp1 dupfilesp2@0 dupfilesp3")
- # XXX The checks here rely on verify failing due to hashes being
- # wrong; they should probably report a duplicate action instead.
- self.pkg("verify", exit=1)
- out1, err1 = self.output, self.errout
- self.pkg("uninstall dupfilesp3")
- # Because we removed dupfilesp3, the error output in this verify
- # won't exactly match that from the previous one, but the one
- # remaining failing package should give the same output since we
- # didn't modify the FS, so search for the current output in the
- # old.
- self.pkg("verify", exit=1)
- out2 = self.output
- # Strip the first (header) line; this error might not have been
- # first in the previous output.
- out2 = out2[out2.index("\n") + 1:]
- self.assert_(out2 in out1)
-
- # Removing all but one of the offending actions should get us
- # back to sanity.
- self.pkg("uninstall '*'")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupfilesp1 dupfilesp2@0 dupfilesp3")
- self.pkg("uninstall dupfilesp3 dupfilesp2")
- self.pkg("verify")
-
- # Make sure we handle cleaning up multiple files properly.
- self.pkg("uninstall '*'")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupfilesp1 dupfilesp2@0 dupotherfilesp1 "
- "dupotherfilesp2")
- self.pkg("uninstall dupfilesp2 dupotherfilesp2")
- self.pkg("verify")
-
- # Make sure we get rid of all implicit directories.
- self.pkg("uninstall '*'")
- self.pkg("exact-install implicitdirs3 implicitdirs4")
- self.pkg("uninstall implicitdirs3 implicitdirs4")
-
- if os.path.isdir(os.path.join(self.get_img_path(), "usr/bin")):
- self.assert_(False, "Directory 'usr/bin' should not exist")
-
- if os.path.isdir(os.path.join(self.get_img_path(), "usr")):
- self.assert_(False, "Directory 'usr' should not exist")
-
- # Make sure identical actions don't cause problems.
- self.pkg("exact-install -nv identicalfiles", exit=1)
-
- # Trigger a bug similar to 17943 via duplicate files.
- self.pkg("publisher")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupfilesp1@0 dupfilesp2@0 dupfilesp3@0 "
- "dupotherfilesp1@0 dupotherfilesp2@0 dupotherfilesp3@0")
- self.pkg("update")
-
def test_overlay_files_install(self):
"""Test the behaviour of pkg(1) when actions for editable files
overlay other actions."""
@@ -9336,7 +8982,10 @@
# overlaying action declares its intent to overlay.
self.pkg("contents -m overlaid")
self.pkg("contents -mr overlayer")
- self.pkg("install overlayer")
+ self.pkg("install --parsable=0 overlayer")
+ self._assertEditables(
+ installed=["etc/pam.conf"],
+ )
self.file_contains("etc/pam.conf", "file2")
# Should fail because multiple actions are not allowed to
@@ -9356,38 +9005,54 @@
# Verify that the file isn't touched on uninstall of the
# overlaying package if package being overlaid is still
# installed.
- self.pkg("uninstall -vvv overlayer")
+ self.pkg("uninstall --parsable=0 overlayer")
+ self._assertEditables()
self.file_contains("etc/pam.conf", "zigit")
self.file_contains("etc/pam.conf", "file2")
# Verify that removing the last package delivering an overlaid
# file removes the file.
- self.pkg("uninstall overlaid")
+ self.pkg("uninstall --parsable=0 overlaid")
+ self._assertEditables(
+ removed=["etc/pam.conf"],
+ )
self.file_doesnt_exist("etc/pam.conf")
# Verify that installing both packages at the same time results
# in only the overlaying file being delivered.
- self.pkg("install overlaid@0 overlayer")
+ self.pkg("install --parsable=0 overlaid@0 overlayer")
+ self._assertEditables(
+ installed=["etc/pam.conf"],
+ )
self.file_contains("etc/pam.conf", "file2")
# Verify that the file isn't touched on uninstall of the
# overlaid package if overlaying package is still installed.
self.file_append("etc/pam.conf", "zigit")
- self.pkg("uninstall overlaid")
+ self.pkg("uninstall --parsable=0 overlaid")
+ self._assertEditables()
self.file_contains("etc/pam.conf", "file2")
self.file_contains("etc/pam.conf", "zigit")
# Re-install overlaid package and verify that file content
# does not change.
- self.pkg("install overlaid@0")
+ self.pkg("install --parsable=0 overlaid@0")
+ self._assertEditables()
self.file_contains("etc/pam.conf", "file2")
self.file_contains("etc/pam.conf", "zigit")
- self.pkg("uninstall overlaid overlayer")
+ self.pkg("uninstall --parsable=0 overlaid overlayer")
+ self._assertEditables(
+ removed=["etc/pam.conf"],
+ )
# Should succeed because one action is overlayable and
# overlaying action declares its intent to overlay even
# though the overlaying action isn't marked with preserve.
- self.pkg("install overlaid@0 unpreserved-overlayer")
+ self.pkg("install -nvv overlaid@0 unpreserved-overlayer")
+ self.pkg("install --parsable=0 overlaid@0 unpreserved-overlayer")
+ self._assertEditables(
+ installed=["etc/pam.conf"],
+ )
self.file_contains("etc/pam.conf", "unpreserved")
# Should succeed because overlaid action permits modification
@@ -9413,7 +9078,8 @@
self.pkg("revert /etc/pam.conf")
self.file_contains("etc/pam.conf", "unpreserved")
self.file_doesnt_contain("etc/pam.conf", "zigit")
- self.pkg("uninstall unpreserved-overlayer")
+ self.pkg("uninstall --parsable=0 unpreserved-overlayer")
+ self._assertEditables()
# Should revert to content delivered by overlaid action.
self.file_contains("etc/pam.conf", "unpreserved")
@@ -9423,21 +9089,28 @@
# Install overlaying package, then update overlaid package and
# verify that file content does not change if only preserve
# attribute changes.
- self.pkg("install -vvv unpreserved-overlayer")
+ self.pkg("install --parsable=0 unpreserved-overlayer")
+ self._assertEditables(
+ installed=["etc/pam.conf"],
+ )
self.file_contains("etc/pam.conf", "unpreserved")
- self.pkg("install overlaid@1")
+ self.pkg("install --parsable=0 overlaid@1")
+ self._assertEditables()
self.file_contains("etc/pam.conf", "unpreserved")
- self.pkg("uninstall -vvv overlaid")
+ self.pkg("uninstall --parsable=0 overlaid")
+ self._assertEditables()
# Now update overlaid package again, and verify that file
# content does not change even though overlaid content has.
- self.pkg("install -vvv overlaid@2")
+ self.pkg("install --parsable=0 overlaid@2")
+ self._assertEditables()
self.file_contains("etc/pam.conf", "unpreserved")
# Now update overlaid package again this time as part of a
# rename, and verify that file content does not change even
# though file has moved between packages.
- self.pkg("install -vvv overlaid@3")
+ self.pkg("install --parsable=0 overlaid@3")
+ self._assertEditables()
self.file_contains("etc/pam.conf", "unpreserved")
# Verify that unpreserved overlay is not salvaged when both
@@ -9452,7 +9125,11 @@
shutil.rmtree(sroot)
# Verify etc directory not found after uninstall.
- self.pkg("uninstall -vvv overlaid-renamed unpreserved-overlayer")
+ self.pkg("uninstall --parsable=0 overlaid-renamed "
+ "unpreserved-overlayer")
+ self._assertEditables(
+ removed=['etc/pam.conf'],
+ )
salvaged = [
n for n in os.listdir(sroot)
if n.startswith("etc")
@@ -9464,15 +9141,28 @@
# the new location and the old location, that the content has
# not changed in either, and that the new configuration exists
# as expected as ".new".
- self.pkg("install -vvv overlaid-renamed@3 unpreserved-overlayer")
- self.pkg("install -vvv [email protected]")
+ self.pkg("install --parsable=0 overlaid-renamed@3 "
+ "unpreserved-overlayer")
+ self._assertEditables(
+ installed=['etc/pam.conf'],
+ )
+ self.pkg("install -nvv [email protected]")
+ self.pkg("install --parsable=0 [email protected]")
+ self._assertEditables(
+ moved=[['etc/pam.conf', 'etc/pam/pam.conf']],
+ installed=['etc/pam/pam.conf.new'],
+ )
self.file_contains("etc/pam.conf", "unpreserved")
self.file_contains("etc/pam/pam.conf", "unpreserved")
self.file_contains("etc/pam/pam.conf.new", "file4")
# Verify etc/pam.conf not salvaged after uninstall as overlay
# file has not been changed.
- self.pkg("uninstall -vvv overlaid-renamed unpreserved-overlayer")
+ self.pkg("uninstall --parsable=0 overlaid-renamed "
+ "unpreserved-overlayer")
+ self._assertEditables(
+ removed=['etc/pam.conf', 'etc/pam/pam.conf'],
+ )
salvaged = [
n for n in os.listdir(os.path.join(sroot, "etc"))
if n.startswith("pam.conf")
@@ -9485,22 +9175,29 @@
# Install overlaying package, then update overlaid package and
# verify that file content does not change if only preserve
# attribute changes.
- self.pkg("install -vvv overlayer")
+ self.pkg("install --parsable=0 overlayer")
+ self._assertEditables(
+ installed=['etc/pam.conf'],
+ )
self.file_contains("etc/pam.conf", "file2")
self.file_append("etc/pam.conf", "zigit")
- self.pkg("install overlaid@1")
+ self.pkg("install --parsable=0 overlaid@1")
+ self._assertEditables()
self.file_contains("etc/pam.conf", "zigit")
- self.pkg("uninstall -vvv overlaid")
+ self.pkg("uninstall --parsable=0 overlaid")
+ self._assertEditables()
# Now update overlaid package again, and verify that file
# content does not change even though overlaid content has.
- self.pkg("install -vvv overlaid@2")
+ self.pkg("install --parsable=0 overlaid@2")
+ self._assertEditables()
self.file_contains("etc/pam.conf", "zigit")
# Now update overlaid package again this time as part of a
# rename, and verify that file content does not change even
# though file has moved between packages.
- self.pkg("install -vvv overlaid@3")
+ self.pkg("install --parsable=0 overlaid@3")
+ self._assertEditables()
self.file_contains("etc/pam.conf", "zigit")
# Verify that preserved overlay is salvaged when both overlaid
@@ -9515,7 +9212,10 @@
shutil.rmtree(sroot)
# Verify etc directory found after uninstall.
- self.pkg("uninstall -vvv overlaid-renamed overlayer")
+ self.pkg("uninstall --parsable=0 overlaid-renamed overlayer")
+ self._assertEditables(
+ removed=['etc/pam.conf'],
+ )
salvaged = [
n for n in os.listdir(sroot)
if n.startswith("etc")
@@ -9528,22 +9228,39 @@
# and the old location, that the content has not changed in
# either, and that the new configuration exists as expected as
# ".new".
- self.pkg("install -vvv overlaid-renamed@3 overlayer")
+ self.pkg("install --parsable=0 overlaid-renamed@3 overlayer")
+ self._assertEditables(
+ installed=['etc/pam.conf'],
+ )
self.file_append("etc/pam.conf", "zigit")
- self.pkg("install -vvv [email protected]")
+ self.pkg("install --parsable=0 [email protected]")
+ self._assertEditables(
+ moved=[['etc/pam.conf', 'etc/pam/pam.conf']],
+ installed=['etc/pam/pam.conf.new'],
+ )
self.file_contains("etc/pam.conf", "zigit")
self.file_contains("etc/pam/pam.conf", "zigit")
self.file_contains("etc/pam/pam.conf.new", "file4")
- self.pkg("uninstall -vvv overlaid-renamed overlayer")
+ self.pkg("uninstall --parsable=0 overlaid-renamed overlayer")
+ self._assertEditables(
+ removed=['etc/pam.conf', 'etc/pam/pam.conf'],
+ )
# Next, update overlaid package again, this time as part of a
# file move. Verify that the configuration file exists at both
# the new location and the old location, that the content has
# not changed in either, and that the new configuration exists
# as expected as ".new".
- self.pkg("install -vvv overlaid-renamed@3 overlayer")
+ self.pkg("install --parsable=0 overlaid-renamed@3 overlayer")
+ self._assertEditables(
+ installed=['etc/pam.conf'],
+ )
self.file_append("etc/pam.conf", "zigit")
- self.pkg("install -vvv [email protected]")
+ self.pkg("install --parsable=0 [email protected]")
+ self._assertEditables(
+ moved=[['etc/pam.conf', 'etc/pam/pam.conf']],
+ installed=['etc/pam/pam.conf.new'],
+ )
self.file_contains("etc/pam.conf", "zigit")
self.file_contains("etc/pam/pam.conf", "zigit")
self.file_contains("etc/pam/pam.conf.new", "file4")
@@ -9551,17 +9268,27 @@
# Next, downgrade the package and verify that if an overlaid
# file moves back to its original location, the content of the
# overlay file will not change.
- self.pkg("update -vvv overlaid-renamed@3")
+ self.pkg("update --parsable=0 overlaid-renamed@3")
+ self._assertEditables(
+ removed=['etc/pam/pam.conf'],
+ )
self.file_contains("etc/pam.conf", "zigit")
# Now upgrade again for remaining tests.
- self.pkg("install -vvv [email protected]")
+ self.pkg("install --parsable=0 [email protected]")
+ self._assertEditables(
+ moved=[['etc/pam.conf', 'etc/pam/pam.conf']],
+ installed=['etc/pam/pam.conf.new'],
+ )
# Verify etc/pam.conf and etc/pam/pam.conf salvaged after
# uninstall as overlay file and overlaid file is different from
# packaged.
shutil.rmtree(sroot)
- self.pkg("uninstall -vvv overlaid-renamed overlayer")
+ self.pkg("uninstall --parsable=0 overlaid-renamed overlayer")
+ self._assertEditables(
+ removed=['etc/pam.conf', 'etc/pam/pam.conf'],
+ )
salvaged = sorted(
n for n in os.listdir(os.path.join(sroot, "etc"))
if n.startswith("pam")
@@ -9579,348 +9306,66 @@
# Next, install overlaid package and overlaying package, then
# upgrade each to a version where the file has changed
# locations and verify that the content remains intact.
- self.pkg("install -vvv overlaid@0 overlayer-move@0")
+ self.pkg("install --parsable=0 overlaid@0 overlayer-move@0")
+ self._assertEditables(
+ installed=['etc/pam.conf'],
+ )
self.file_append("etc/pam.conf", "zigit")
- self.pkg("install -vvv overlaid@3")
+ self.pkg("install --parsable=0 overlaid@3")
+ self._assertEditables()
self.file_contains("etc/pam.conf", "zigit")
- self.pkg("install -vvv [email protected] overlayer-move@1")
+ self.pkg("install --parsable=0 [email protected] "
+ "overlayer-move@1")
+ self._assertEditables(
+ moved=[['etc/pam.conf', 'etc/pam/pam.conf']],
+ )
self.file_contains("etc/pam/pam.conf", "zigit")
# Next, downgrade overlaid-renamed and overlaying package to
# versions where the file is restored to its original location
# and verify that the content is reverted to the original
# overlay version since this is a downgrade.
- self.pkg("update -vvv overlaid-renamed@3 overlayer-move@0")
+ self.pkg("update --parsable=0 overlaid-renamed@3 "
+ "overlayer-move@0")
+ self._assertEditables(
+ removed=['etc/pam/pam.conf'],
+ installed=['etc/pam.conf'],
+ )
self.file_contains("etc/pam.conf", "file2")
- self.pkg("uninstall overlaid-renamed overlayer-move")
+ self.pkg("uninstall --parsable=0 overlaid-renamed overlayer-move")
+ self._assertEditables(
+ removed=['etc/pam.conf'],
+ )
# Next, install overlaid package and overlaying package and
# verify preserve acts as expected for overlay package as it is
# updated.
- self.pkg("install -vvv overlaid@2 overlayer-update@0")
+ self.pkg("install --parsable=0 overlaid@2 overlayer-update@0")
+ self._assertEditables(
+ installed=['etc/pam.conf'],
+ )
self.file_contains("etc/pam.conf", "file1")
# unpreserved -> preserved
- self.pkg("install -vvv overlayer-update@1")
+ self.pkg("install --parsable=0 overlayer-update@1")
+ self._assertEditables(
+ updated=['etc/pam.conf'],
+ )
self.file_contains("etc/pam.conf", "file2")
self.file_append("etc/pam.conf", "zigit")
# preserved -> renameold
- self.pkg("install -vvv overlayer-update@2")
+ self.pkg("install --parsable=0 overlayer-update@2")
+ self._assertEditables(
+ moved=[['etc/pam.conf', 'etc/pam.conf.old']],
+ installed=['etc/pam.conf'],
+ )
self.file_doesnt_contain("etc/pam.conf", "zigit")
self.file_contains("etc/pam.conf.old", "zigit")
self.file_append("etc/pam.conf", "zagat")
# renameold -> renamenew
- self.pkg("install -vvv overlayer-update@3")
- self.file_contains("etc/pam.conf", "zagat")
- self.file_contains("etc/pam.conf.new", "file4")
-
- def test_overlay_files_exact_install(self):
- """Test the behaviour of pkg(1) when actions for editable files
- overlay other actions."""
-
- # Ensure that overlay is allowed for file actions when one
- # action has specified preserve attribute and overlay=allow,
- # and *one* (only) other action has specified overlay=true
- # (preserve does not have to be set).
- self.image_create(self.rurl)
-
- # With exact-install, this should succeed because exact-install
- # will remove the previously installed package first.
- # but not preserve (it isn't editable).
- self.pkg("exact-install invalid-overlaid")
- self.pkg("exact-install overlayer")
- self.pkg("uninstall overlayer")
-
- self.pkg("exact-install overlaid@0")
- self.file_contains("etc/pam.conf", "file1")
- # Should succeed with exact-install, because the previous
- # package is actually removed.
- self.pkg("contents -m overlaid")
- self.pkg("contents -mr overlayer")
- self.pkg("exact-install overlayer")
- self.file_contains("etc/pam.conf", "file2")
-
- # install back overlaid@0
- self.pkg("exact-install overlaid@0")
- self.pkg("verify overlaid")
- self.file_contains("etc/pam.conf", "file1")
- # This should also succeed with exact-install, because the
- # previous package is removed.
- self.pkg("exact-install invalid-overlayer")
- self.file_contains("etc/pam.conf", "file2")
- self.pkg("verify invalid-overlayer")
- # This should also succeed with exact-install. Again.
- self.pkg("exact-install overlaid@0")
- self.pkg("exact-install mismatch-overlayer")
- self.file_contains("etc/pam.conf", "file2")
- self.pkg("verify mismatch-overlayer")
- # This should alos succeed with exact-install, same reason.
- self.pkg("exact-install overlaid@0")
- self.pkg("exact-install multi-overlayer")
- self.file_contains("etc/pam.conf", "file2")
- self.pkg("verify multi-overlayer")
- # Verify that removing the last package delivering an overlaid
- # file removes the file.
- self.pkg("uninstall multi-overlayer")
- self.file_doesnt_exist("etc/pam.conf")
-
- # Verify that exact-installing both packages at the same time
- # results in only the overlaying file being delivered.
- self.pkg("exact-install overlaid@0 overlayer")
- self.file_contains("etc/pam.conf", "file2")
-
- # Verify that the file isn't touched on uninstall of the
- # overlaid package if overlaying package is still installed.
- self.file_append("etc/pam.conf", "zigit")
- self.pkg("uninstall overlaid")
- self.file_contains("etc/pam.conf", "file2")
- self.file_contains("etc/pam.conf", "zigit")
-
- # Re-install overlaid package and verify that file content
- # does not change.
- self.pkg("exact-install overlaid@0")
- self.file_contains("etc/pam.conf", "file2")
- self.file_contains("etc/pam.conf", "zigit")
- self.pkg("uninstall '*'")
-
- # Should succeed because one action is overlayable and
- # overlaying action declares its intent to overlay even
- # though the overlaying action isn't marked with preserve.
- self.pkg("exact-install overlaid@0 unpreserved-overlayer")
- self.file_contains("etc/pam.conf", "unpreserved")
-
- # Should succeed because overlaid action permits modification
- # and contents matches overlaying action.
- self.pkg("verify overlaid unpreserved-overlayer")
-
- # Should succeed even though file has been modified since
- # overlaid action permits modification.
- self.file_append("etc/pam.conf", "zigit")
- self.pkg("verify overlaid")
-
- # Should fail because overlaying action does not permit
- # modification.
- self.pkg("verify unpreserved-overlayer", exit=1)
-
- # Should revert to content delivered by overlaying action.
- self.pkg("fix unpreserved-overlayer")
- self.file_contains("etc/pam.conf", "unpreserved")
- self.file_doesnt_contain("etc/pam.conf", "zigit")
-
- # Should revert to content delivered by overlaying action.
- self.file_append("etc/pam.conf", "zigit")
- self.pkg("revert /etc/pam.conf")
- self.file_contains("etc/pam.conf", "unpreserved")
- self.file_doesnt_contain("etc/pam.conf", "zigit")
- self.pkg("uninstall unpreserved-overlayer")
-
- # Should revert to content delivered by overlaid action.
- self.file_contains("etc/pam.conf", "unpreserved")
- self.pkg("revert /etc/pam.conf")
- self.file_contains("etc/pam.conf", "file1")
-
- # Here if we use exact-install, we actually removed the
- # unpreserved-overlayer and then unpreserved should disappear
- # from etc/pam.conf.
- self.pkg("exact-install -vvv unpreserved-overlayer")
- self.file_contains("etc/pam.conf", "unpreserved")
- self.pkg("exact-install overlaid@1")
- self.file_contains("etc/pam.conf", "file1")
- self.file_doesnt_contain("etc/pam.conf", "unpreserved")
- self.pkg("uninstall -vvv overlaid")
-
- # Now update overlaid package, and verify that it deliver the
- # correct files
- self.pkg("exact-install -vvv overlaid@2")
- self.file_contains("etc/pam.conf", "file3")
-
- self.pkg("exact-install -vvv overlaid@3")
- self.file_contains("etc/pam.conf", "file3")
-
- # Verify that unpreserved overlay is not salvaged when both
- # overlaid and overlaying package are removed at the same time.
- # (Preserved files are salvaged if they have been modified on
- # uninstall.)
-
- # Ensure directory is empty before testing.
- api_inst = self.get_img_api_obj()
- img_inst = api_inst.img
- sroot = os.path.join(img_inst.imgdir, "lost+found")
- shutil.rmtree(sroot)
-
- # Verify etc directory not found after uninstall.
- self.pkg("uninstall -vvv overlaid-renamed")
- salvaged = [
- n for n in os.listdir(sroot)
- if n.startswith("etc")
- ]
- self.assertEqualDiff(salvaged, [])
-
- # Next, update overlaid package again this time as part of a
- # file move. Verify that the old configuration file should
- # be removed.
- self.pkg("exact-install -vvv overlaid-renamed@3 "
- "unpreserved-overlayer")
- self.pkg("exact-install -vvv [email protected]")
- self.assert_(not os.path.exists(os.path.join(
- self.get_img_path(), "etc/pam.conf")))
- self.file_contains("etc/pam/pam.conf.new", "file4")
-
- # Verify etc/pam/pam.conf is salvaged after uninstall as
- # overlay file has been changed.
- self.pkg("uninstall -vvv overlaid-renamed")
- salvaged = [
- n for n in os.listdir(os.path.join(sroot, "etc/pam"))
- if n.startswith("pam.conf")
- ]
- self.assert_(salvaged[0].startswith("pam.conf-"),
- msg=str(salvaged))
-
- # Next, repeat the same set of tests performed above for
- # renames and moves with an overlaying, preserved file.
- #
- # Exact-install overlaying package, then update overlaid
- # package and verify that file content does not change if only
- # preserve attribute changes.
- self.pkg("exact-install -vvv overlayer")
- self.file_contains("etc/pam.conf", "file2")
- self.file_append("etc/pam.conf", "zigit")
- self.pkg("exact-install -vvv overlaid@1")
- self.file_contains("etc/pam.conf", "file2")
- self.file_contains("etc/pam.conf", "zigit")
-
- # Now update overlaid package again, and verify that file
- # content does not change even though overlaid content has.
- self.pkg("exact-install -vvv overlaid@2")
- self.file_contains("etc/pam.conf", "zigit")
- self.file_contains("etc/pam.conf", "file2")
-
- # Now update overlaid package again this time as part of a
- # rename, and verify that file content does not change even
- # though file has moved between packages.
- self.pkg("exact-install -vvv overlaid@3")
- self.file_contains("etc/pam.conf", "zigit")
-
- # Verify that preserved overlay is salvaged.
- # (Preserved files are salvaged if they have been modified on
- # uninstall.)
-
- # Ensure directory is empty before testing.
- api_inst = self.get_img_api_obj()
- img_inst = api_inst.img
- sroot = os.path.join(img_inst.imgdir, "lost+found")
- shutil.rmtree(sroot)
-
- # Verify etc directory found after uninstall.
- self.pkg("uninstall -vvv overlaid-renamed")
- salvaged = [
- n for n in os.listdir(sroot)
- if n.startswith("etc")
- ]
- self.assert_(salvaged[0].startswith("etc"),
- msg=str(salvaged))
- self.assert_(salvaged[1].startswith("etc-"),
- msg=str(salvaged))
-
- # Next, update overlaid package again, this time as part of a
- # file move where the overlay attribute was dropped. Verify
- # that the content has not changed after move to new location
- # and that the new configuration exists as expected as
- # ".new".
- self.pkg("exact-install -vvv overlaid-renamed@3 overlayer")
- self.file_append("etc/pam.conf", "zigit")
- self.pkg("exact-install -vvv [email protected]")
- self.file_contains("etc/pam/pam.conf", "zigit")
- self.file_contains("etc/pam/pam.conf.new", "file4")
- self.pkg("uninstall -vvv overlaid-renamed")
-
- # Next, update overlaid package again, this time as part of a
- # file move where the overlay attribute was dropped. Verify
- # that the content has not changed after move to new location
- # and that the new configuration exists as expected as
- # ".new".
- self.pkg("exact-install -vvv overlaid-renamed@3 overlayer")
- self.file_append("etc/pam.conf", "zigit")
- self.file_contains("etc/pam.conf", "file2")
- self.pkg("exact-install -vvv [email protected]")
- self.file_contains("etc/pam/pam.conf", "zigit")
- self.file_contains("etc/pam/pam.conf.new", "file4")
-
- # Next, downgrade the package and verify that if an overlaid
- # file moves back to its original location. Because the
- # previous etc/pam.conf for overlayer was removed by
- # exact-install, the content of the overlay file will be a new
- # one.
- self.pkg("update -vvv overlaid-renamed@3")
- self.file_contains("etc/pam.conf", "file3")
- self.file_doesnt_contain("etc/pam.conf", "zigit")
- self.file_append("etc/pam.conf", "zigit")
- # Now upgrade again for remaining tests.
- self.pkg("exact-install -vvv [email protected]")
-
- # Verify etc/pam.conf and etc/pam/pam.conf salvaged after
- # uninstall as overlay file and overlaid file is different from
- # packaged.
- shutil.rmtree(sroot)
- self.pkg("uninstall -vvv overlaid-renamed")
- salvaged = sorted(
- n for n in os.listdir(os.path.join(sroot, "etc"))
- if n.startswith("pam")
+ self.pkg("install --parsable=0 overlayer-update@3")
+ self._assertEditables(
+ installed=['etc/pam.conf.new'],
)
- # Should have three entries; one should be 'pam' directory
- # (presumably containing pam.conf-X...), a 'pam-XXX' directory,
- # and a etc-XXX directory.
- self.assertEqualDiff(salvaged[0], "pam")
- self.assert_(salvaged[1].startswith("pam-"),
- msg=str(salvaged))
-
- salvaged = sorted(
- n for n in os.listdir(os.path.join(sroot, "etc/pam"))
- if n.startswith("pam")
- )
- self.assert_(salvaged[0].startswith("pam.conf-"),
- msg=str(salvaged))
- salvaged = sorted(
- n for n in os.listdir(sroot)
- if n.startswith("etc-")
- )
- self.assert_(salvaged[0].startswith("etc-"),
- msg=str(salvaged))
-
- # Next, exact-install overlaid package and overlaying package,
- # then upgrade each to a version where the file has changed
- # locations and verify that the content remains intact.
- self.pkg("exact-install -vvv overlaid@0 overlayer-move@0")
- self.file_append("etc/pam.conf", "zigit")
- self.pkg("exact-install -vvv overlaid@3 overlayer-move@0")
- self.file_contains("etc/pam.conf", "zigit")
- self.pkg("exact-install -vvv [email protected] "
- "overlayer-move@1")
- self.file_contains("etc/pam/pam.conf", "zigit")
-
- # Next, downgrade overlaid-renamed and overlaying package to
- # versions where the file is restored to its original location
- # and verify that the content is reverted to the original
- # overlay version since this is a downgrade.
- self.pkg("update -vvv overlaid-renamed@3 overlayer-move@0")
- self.file_contains("etc/pam.conf", "file2")
- self.pkg("uninstall overlaid-renamed overlayer-move")
-
- # Next, exact-install overlaid package and overlaying package
- # and verify preserve acts as expected for overlay package as
- # it is updated.
- self.pkg("exact-install -vvv overlaid@2 overlayer-update@0")
- self.file_contains("etc/pam.conf", "file1")
- # unpreserved -> preserved
- self.pkg("exact-install -vvv overlayer-update@1")
- self.file_contains("etc/pam.conf", "file2")
- self.file_append("etc/pam.conf", "zigit")
- # preserved -> renameold
- self.pkg("exact-install -vvv overlayer-update@2")
- self.file_doesnt_contain("etc/pam.conf", "zigit")
- self.file_contains("etc/pam.conf.old", "zigit")
- self.file_append("etc/pam.conf", "zagat")
- # renameold -> renamenew
- self.pkg("exact-install -vvv overlayer-update@3")
self.file_contains("etc/pam.conf", "zagat")
self.file_contains("etc/pam.conf.new", "file4")
@@ -10069,152 +9514,6 @@
self.pkg("install dupmultitypes3@0")
self.pkg("update")
- def test_different_types_exact_install(self):
- """Test the behavior of pkg(1) when multiple actions of
- different types deliver to the same pathname."""
-
- self.image_create(self.rurl)
-
- # In the same package.
- self.pkg("exact-install duppath-filelink", exit=1)
-
- # In different packages, in the same transaction.
- self.pkg("exact-install dupfilesp1 duplink", exit=1)
-
- # In different packages, in different transactions. This should
- # succeed because exact-install will first uninstall
- # dupfilesp1.
- self.pkg("exact-install dupfilesp1")
- self.pkg("exact-install duplink")
-
- # Does removal of one of the busted packages get us out of the
- # situation?
- self.pkg("uninstall '*'")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupfilesp1 duplink")
- self.pkg("verify", exit=1)
- self.pkg("uninstall dupfilesp1")
- self.pkg("verify")
-
- # Implicit directory conflicts with a file
- self.pkg("uninstall '*'")
- self.pkg("exact-install implicitdirs", exit=1)
-
- # Implicit directory coincides with a delivered directory.
- self.pkg("exact-install implicitdirs2")
-
- # Make sure that we don't die trying to fixup a directory using
- # an implicit directory action.
- self.pkg("uninstall '*'")
- self.pkg("exact-install implicitdirs4")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "install implicitdirs7")
- self.pkg("uninstall implicitdirs7")
- # XXX We don't currently fix up anything beneath a directory
- # that was restored, so we have to do it by hand.
- os.mkdir("%s/usr/bin" % self.img_path())
- shutil.copy("%s/tmp/file1" % self.test_root,
- "%s/usr/bin/something" % self.img_path())
- owner = portable.get_user_by_name("root", self.img_path(), True)
- group = portable.get_group_by_name("bin", self.img_path(), True)
- os.chown("%s/usr/bin/something" % self.img_path(), owner, group)
- os.chmod("%s/usr/bin/something" % self.img_path(), 0755)
- self.pkg("verify")
-
- # Removing one of more than two offending actions can't do much
- # of anything, but should leave the system alone.
- self.pkg("uninstall '*'")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupfilesp1 duplink dupdir@0")
- tmap = {
- stat.S_IFIFO: "fifo",
- stat.S_IFCHR: "character device",
- stat.S_IFDIR: "directory",
- stat.S_IFBLK: "block device",
- stat.S_IFREG: "regular file",
- stat.S_IFLNK: "symbolic link",
- stat.S_IFSOCK: "socket",
- }
- thepath = "%s/dir/pathname" % self.img_path()
- fmt = stat.S_IFMT(os.lstat(thepath).st_mode)
- # XXX The checks here rely on verify failing due to action types
- # not matching what's on the system; they should probably report
- # duplicate actions instead. Checking the output text is a bit
- # ugly, too, but we do need to make sure that the two problems
- # become one.
- self.pkg("verify", exit=1)
- verify_type_re = "File Type: '(.*?)' should be '(.*?)'"
- matches = re.findall(verify_type_re, self.output)
- # We make sure that what got reported is correct -- two actions
- # of different types in conflict with whatever actually got laid
- # down.
- self.assert_(len(matches) == 2)
- whatis = matches[0][0]
- self.assert_(matches[1][0] == whatis)
- self.assert_(whatis == tmap[fmt])
- shouldbe = set(["symbolic link", "regular file", "directory"]) - \
- set([whatis])
- self.assert_(set([matches[0][1], matches[1][1]]) == shouldbe)
- # Now we uninstall one of the packages delivering a type which
- # isn't what's on the filesystem. The filesystem should remain
- # unchanged, but one of the errors should go away.
- if whatis == "directory":
- self.pkg("uninstall duplink")
- else:
- self.pkg("uninstall dupdir")
- self.pkg("verify", exit=1)
- matches = re.findall(verify_type_re, self.output)
- self.assert_(len(matches) == 1)
- nfmt = stat.S_IFMT(os.lstat(thepath).st_mode)
- self.assert_(nfmt == fmt)
-
- # Now we do the same thing, but we uninstall the package
- # delivering the type which *is* what's on the filesystem. This
- # should also leave the filesystem alone, even though what's
- # there will match *neither* of the remaining installed
- # packages.
- self.pkg("uninstall '*'")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupfilesp1 duplink dupdir@0")
- fmt = stat.S_IFMT(os.lstat(thepath).st_mode)
- self.pkg("verify", exit=1)
- matches = re.findall(verify_type_re, self.output)
- self.assert_(len(matches) == 2)
- whatis = matches[0][0]
- self.assert_(matches[1][0] == whatis)
- self.assert_(whatis == tmap[fmt])
- shouldbe = set(["symbolic link", "regular file", "directory"]) - \
- set([whatis])
- self.assert_(set([matches[0][1], matches[1][1]]) == shouldbe)
- if whatis == "directory":
- self.pkg("uninstall dupdir")
- elif whatis == "symbolic link":
- self.pkg("uninstall duplink")
- elif whatis == "regular file":
- self.pkg("uninstall dupfilesp1")
- self.pkg("verify", exit=1)
- matches = re.findall(verify_type_re, self.output)
- self.assert_(len(matches) == 2)
- nfmt = stat.S_IFMT(os.lstat(thepath).st_mode)
- self.assert_(nfmt == fmt)
-
- # Go from multiple conflicting types down to just one type.
- # This also tests the case where a package version being newly
- # installed gets fixed at the same time.
- self.pkg("uninstall '*'")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupmultitypes@1")
- self.pkg("exact-install dupmultitypes")
- self.pkg("verify")
-
- # Upgrading from multiple instances of one refcounted type to
- # multiple instances of another (here, link to directory)
- # should succeed.
- self.pkg("uninstall '*'")
- self.pkg("exact-install dupmultitypes3@0")
- self.pkg("update")
-
-
def test_conflicting_attrs_fs_install(self):
"""Test the behavior of pkg(1) when multiple non-file actions of
the same type deliver to the same pathname, but whose other
@@ -10379,180 +9678,12 @@
"dupdirp12")
self.pkg("uninstall dupdirp12")
- def test_conflicting_attrs_fs_exact_install(self):
- """Test the behavior of pkg(1) when multiple non-file actions of
- the same type deliver to the same pathname, but whose other
- attributes differ."""
-
- self.image_create(self.rurl)
-
- # One package, two links with different targets
- self.pkg("exact-install duppath-nonidenticallinks", exit=1)
-
- # One package, two directories with different perms
- self.pkg("exact-install duppath-nonidenticaldirs", exit=1)
-
- # One package, two dirs with same modes expressed two ways
- self.pkg("exact-install duppath-almostidenticaldirs")
-
- # One package delivers a directory explicitly, another
- # implicitly.
- self.pkg("exact-install implicitdirs2 implicitdirs3")
- self.pkg("verify")
-
- self.pkg("uninstall '*'")
-
- # Make sure that we don't die trying to fixup a directory using
- # an implicit directory action.
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install implicitdirs4 implicitdirs5 implicitdirs6")
- self.pkg("uninstall implicitdirs5")
- self.pkg("verify")
-
- self.pkg("uninstall '*'")
-
- # Make sure that we don't die trying to fixup a directory using
- # an implicit directory action when that's all that's left.
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install implicitdirs4 implicitdirs5 implicitdirs6")
- self.pkg("uninstall implicitdirs5 implicitdirs6")
- self.pkg("verify")
-
- self.pkg("uninstall '*'")
-
- # If two packages deliver conflicting directories and another
- # package delivers that directory implicitly, make sure the
- # third package isn't blamed.
- self.pkg("exact-install implicitdirs4 implicitdirs5 "
- "implicitdirs6", exit=1)
- self.assert_("implicitdirs4" not in self.errout)
-
- # Two packages, two links with different targets, installed at
- # once
- self.pkg("exact-install duppath-nonidenticallinksp1 "
- "duppath-nonidenticallinksp2@0", exit=1)
-
- # Two packages, two links with different targets, installed
- # separately. again with exact-install the operation will
- # will succeed becauseit will remove the
- # duppath-nonidenticallinksp1 pkg first.
- self.pkg("exact-install duppath-nonidenticallinksp1")
- self.pkg("exact-install duppath-nonidenticallinksp2@0")
-
- self.pkg("uninstall '*'")
-
- # If we get into a broken state, can we get out of it?
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install duppath-nonidenticallinksp1 "
- "duppath-nonidenticallinksp2@0")
- self.pkg("verify", exit=1)
- self.pkg("exact-install duppath-nonidenticallinksp2")
- self.pkg("verify")
-
- # If we get into a broken state, can we make it a little bit
- # better by uninstalling one of the packages? Removing dupdir5
- # here won't reduce the number of different groups under which
- # dir is delivered, but does reduce the number of actions
- # delivering it.
- self.pkg("uninstall '*'")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupdirp1 dupdirp2@1 dupdirp5 dupdirp6")
- self.pkg("uninstall dupdirp5")
- self.pkg("verify", exit=1)
-
- self.pkg("-D broken-conflicting-action-handling=1 install "
- "dupdirp5")
- # Make sure we can exact-install a package delivering an
- # implicit directory that's currently in conflict.
- self.pkg("exact-install dupdirp7")
- # And make sure we can uninstall it again.
- self.pkg("uninstall dupdirp7")
- self.pkg("list", exit=1)
-
- # Add everything back in, remove everything but one variant of
- # the directory and an implicit directory, and verify.
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupdirp2@1 dupdirp5 dupdirp6 dupdirp7")
- self.pkg("uninstall dupdirp2 dupdirp5 dupdirp6")
- self.pkg("verify")
-
- # Get us into a saner state by upgrading.
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupdirp2@1 dupdirp5 dupdirp6 dupdirp7")
- self.pkg("update dupdirp2@2")
-
- # Get us into a sane state by upgrading.
- self.pkg("uninstall dupdirp2 dupdirp5 dupdirp6")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupdirp2@1 dupdirp7")
- self.pkg("update dupdirp2@2")
- self.pkg("verify")
-
- # We start in a sane state, but the update would result in
- # conflict, though no more actions deliver the path in
- # question.
- self.pkg("uninstall '*'")
- self.pkg("exact-install dupdirp1 dupdirp8@1")
- self.pkg("update", exit=1)
-
- # How about removing one of the conflicting packages? We'll
- # remove the package which doesn't match the state on disk.
- self.pkg("uninstall '*'")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install duppath-nonidenticallinksp1 "
- "duppath-nonidenticallinksp2@0")
- link = os.readlink("%s/dir/pathname" % self.img_path())
- if link == "dir/something":
- self.pkg("uninstall duppath-nonidenticallinksp2")
- else:
- self.pkg("uninstall duppath-nonidenticallinksp1")
- self.pkg("verify")
-
- # Now we'll try removing the package which *does* match the
- # state on disk. The code should clean up after us.
- self.pkg("uninstall '*'")
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install duppath-nonidenticallinksp1 "
- "duppath-nonidenticallinksp2@0")
- link = os.readlink("%s/dir/pathname" % self.img_path())
- if link == "dir/something":
- self.pkg("uninstall duppath-nonidenticallinksp1")
- else:
- self.pkg("uninstall duppath-nonidenticallinksp2")
- self.pkg("verify")
-
- # Let's try a duplicate directory delivered with all sorts of
- # crazy conflicts!
- self.pkg("uninstall '*'")
- self.pkg("exact-install dupdirp1 dupdirp2@1 dupdirp3 dupdirp4",
- exit=1)
-
- pkgs = " ".join("massivedupdir%d" % x for x in xrange(20))
- self.pkg("exact-install %s" % pkgs, exit=1)
-
- # Trigger bug 17943: we install packages with conflicts in two
- # directories (p9, p10). We also install a package (p11) which
- # delivers those directories implicitly. Then remove the last,
- # triggering the stack trace associated with the bug.
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupdirp9 dupdirp10 dupdirp11")
- self.pkg("uninstall dupdirp11")
-
- # Do the same, but with a package that delivers var implicitly
- # via a legacy action.
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install dupdirp9 dupdirp10 dupdirp12")
- self.pkg("uninstall dupdirp12")
-
def test_conflicting_attrs_fs_varcets(self):
"""Test the behavior of pkg(1) when multiple non-file actions of
the same type deliver to the same pathname, but differ in their
variants or facets."""
- self.conflicting_attrs_fs_varcets_helper("install")
- self.conflicting_attrs_fs_varcets_helper("exact-install")
-
- def conflicting_attrs_fs_varcets_helper(self, install_cmd):
+ install_cmd = "install"
self.image_create(self.rurl)
# Two packages delivering the same directory, one under the
@@ -10767,61 +9898,6 @@
"otheruser othergroup@0")
self.pkg("update othergroup")
- def test_multiple_users_exact_install(self):
- """Test the behavior of pkg(1) when multiple user
- actions deliver the same user."""
-
- # This is largely identical to test_multiple_files; we may want
- # to commonize in the future.
-
- self.image_create(self.rurl)
-
- self.pkg("exact-install userdb")
-
- # Duplicate users in the same package
- self.pkg("exact-install dupuser", exit=1)
- # Make sure userdb is not accedentally removed.
- self.pkg("list userdb")
-
- # Duplicate users in different packages, but in the same
- # transaction
- self.pkg("exact-install userdb dupuserp1 dupuserp2@0", exit=1)
-
- # Duplicate users in different packages, in different
- # transactions. This should succeed with exact-install.
- self.pkg("exact-install userdb dupuserp1")
- self.pkg("exact-install userdb dupuserp2@0")
-
- # Removing one of more than two offending actions can't do much
- # of anything, but should leave the system alone.
- self.image_destroy()
- self.image_create(self.rurl)
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install userdb dupuserp1 dupuserp2@0 dupuserp3")
- self.pkg("verify", exit=1)
- out1 = self.output
- self.pkg("uninstall dupuserp3")
- self.pkg("verify", exit=1)
- out2 = self.output
- out2 = out2[out2.index("\n") + 1:]
- self.assert_(out2 in out1)
-
- # Removing all but one of the offending actions should get us
- # back to sanity.
- self.image_destroy()
- self.image_create(self.rurl)
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install userdb dupuserp1 dupuserp2@0 dupuserp3")
- self.pkg("uninstall dupuserp3 dupuserp2")
- self.pkg("verify")
-
- # Make sure we don't get confused when two actions in different
- # namespace groups but with the same key attribute value are
- # adjacent in the action cache.
- self.pkg("-D broken-conflicting-action-handling=1 "
- "exact-install userdb otheruser othergroup@0")
- self.pkg("update othergroup")
-
def test_multiple_drivers(self):
"""Test the behavior of pkg(1) when multiple driver actions
deliver the same driver."""