def evaluate(self, old_excludes=EmptyI, new_excludes=EmptyI):
        """Determine the actions required to transition the package."""
        # if origin unset, determine if we're dealing with an previously
        # installed version or if we're dealing with the null package
        #
        # XXX Perhaps make the pkgplan creator make this explicit, so we
        # don't have to check?
        f = None

        if not self.origin_fmri:
            f = self.image.older_version_installed(self.destination_fmri)
            if f:
                self.origin_fmri = f
                self.__origin_mfst = \
self.image.get_manifest(f)

        # Assume that origin actions are unique, but make sure that
        # destination ones are.
        ddups = self.__destination_mfst.duplicates(new_excludes)
        if ddups:
            raise RuntimeError, ["Duplicate actions", ddups]

        self.actions = self.__destination_mfst.difference(
            self.__origin_mfst, old_excludes, new_excludes)

        # figure out how many implicit directories disappear in this
        # transition and add directory remove actions.  These won't
        # do anything unless no pkgs reference that directory in
        # new state....

        # Retrieving origin_dirs first and then checking it for any
        # entries allows avoiding an unnecessary expanddirs for the
        # destination manifest when it isn't needed.
        origin_dirs = expanddirs(
            self.__origin_mfst.get_directories(old_excludes))

        if origin_dirs:
            absent_dirs = origin_dirs - \
                expanddirs(self.__destination_mfst.get_directories(
                new_excludes))

            for a in absent_dirs:
                self.actions[2].append(
                    [directory.DirectoryAction(path=a), None])

        # Stash information needed by legacy actions.
        self.__legacy_info["description"] = \
            self.__destination_mfst.get("pkg.summary",
            self.__destination_mfst.get("description", "none provided"))

        # Add any repair actions to the update list
        self.actions[1].extend(self.__repair_actions)

        #
        # We cross a point of no return here, and throw away the origin
        # and destination manifests; we also delete them from the
        # image cache.
        self.__origin_mfst = None
        self.__destination_mfst = None
Exemple #2
0
    def evaluate(self, old_excludes=EmptyI, new_excludes=EmptyI):
        """Determine the actions required to transition the package."""

        # Assume that origin actions are unique, but make sure that
        # destination ones are.
        ddups = self.__destination_mfst.duplicates(new_excludes)
        if ddups:
            raise RuntimeError(["Duplicate actions", ddups])

        self.actions = self.__destination_mfst.difference(
            self.__origin_mfst, old_excludes, new_excludes)

        # figure out how many implicit directories disappear in this
        # transition and add directory remove actions.  These won't
        # do anything unless no pkgs reference that directory in
        # new state....

        # Retrieving origin_dirs first and then checking it for any
        # entries allows avoiding an unnecessary expanddirs for the
        # destination manifest when it isn't needed.
        origin_dirs = expanddirs(
            self.__origin_mfst.get_directories(old_excludes))

        # No longer needed.
        self.__origin_mfst = None

        if origin_dirs:
            absent_dirs = origin_dirs - \
                expanddirs(self.__destination_mfst.get_directories(
                new_excludes))

            for a in absent_dirs:
                self.actions.removed.append(
                    [directory.DirectoryAction(path=a), None])

        # Stash information needed by legacy actions.
        self.pkg_summary = \
            self.__destination_mfst.get("pkg.summary",
            self.__destination_mfst.get("description", "none provided"))

        # No longer needed.
        self.__destination_mfst = None

        # Add any repair actions to the update list
        self.actions.changed.extend(self.__repair_actions)

        for src, dest in itertools.chain(self.gen_update_actions(),
                                         self.gen_install_actions()):
            if dest.name == "license":
                self.__add_license(src, dest)
Exemple #3
0
    def evaluate(self,
                 old_excludes=EmptyI,
                 new_excludes=EmptyI,
                 can_exclude=False):
        """Determine the actions required to transition the package."""

        # If new actions are being installed, check the destination
        # manifest for signatures.
        if self.destination_fmri is not None:
            try:
                dest_pub = self.image.get_publisher(
                    prefix=self.destination_fmri.publisher)
            except apx.UnknownPublisher:
                # Since user removed publisher, assume this is
                # the same as if they had set signature-policy
                # ignore for the publisher.
                sig_pol = None
            else:
                sig_pol = self.image.signature_policy.combine(
                    dest_pub.signature_policy)

            if self.destination_fmri in self._autofix_pkgs:
                # Repaired packages use a manifest synthesized
                # from the installed one; so retrieve the
                # installed one for our signature checks.
                sigman = self.image.get_manifest(self.destination_fmri,
                                                 ignore_excludes=True)
            else:
                sigman = self.__destination_mfst

            sigs = list(
                sigman.gen_actions_by_type("signature", excludes=new_excludes))
            if sig_pol and (sigs or sig_pol.name != "ignore"):
                # Only perform signature verification logic if
                # there are signatures or if signature-policy
                # is not 'ignore'.

                try:
                    sig_pol.process_signatures(
                        sigs, sigman.gen_actions(), dest_pub,
                        self.image.trust_anchors,
                        self.image.cfg.get_policy(
                            "check-certificate-revocation"))
                except apx.SigningException as e:
                    e.pfmri = self.destination_fmri
                    if isinstance(e, apx.BrokenChain):
                        e.ext_exs.extend(self.image.bad_trust_anchors)
                    raise
        if can_exclude:
            if self.__destination_mfst is not None:
                self.__destination_mfst.exclude_content(new_excludes)
            if self.__origin_mfst is not None and \
                self.__destination_mfst != self.__origin_mfst:
                self.__origin_mfst.exclude_content(old_excludes)
            old_excludes = EmptyI
            new_excludes = EmptyI

        self.actions = self.__destination_mfst.difference(self.__origin_mfst,
                                                          old_excludes,
                                                          new_excludes,
                                                          pkgplan=self)

        # figure out how many implicit directories disappear in this
        # transition and add directory remove actions.  These won't
        # do anything unless no pkgs reference that directory in
        # new state....

        # Retrieving origin_dirs first and then checking it for any
        # entries allows avoiding an unnecessary expanddirs for the
        # destination manifest when it isn't needed.
        origin_dirs = expanddirs(
            self.__origin_mfst.get_directories(old_excludes))

        # Manifest.get_directories() returns implicit directories, which
        # means that this computation ends up re-adding all the explicit
        # directories getting removed to the removed list.  This is
        # ugly, but safe.
        if origin_dirs:
            absent_dirs = origin_dirs - \
                expanddirs(self.__destination_mfst.get_directories(
                new_excludes))

            for a in absent_dirs:
                self.actions.removed.append(
                    (directory.DirectoryAction(path=a, implicit="True"), None))

        # Stash information needed by legacy actions.
        self.pkg_summary = \
            self.__destination_mfst.get("pkg.summary",
            self.__destination_mfst.get("description", "none provided"))

        # Add any install repair actions to the update list
        self.actions.changed.extend(
            self.__repair_actions.get("install", EmptyI))
        self.actions.removed.extend(self.__repair_actions.get(
            "remove", EmptyI))

        # No longer needed.
        self.__repair_actions = {}

        for src, dest in itertools.chain(self.gen_update_actions(),
                                         self.gen_install_actions()):
            if dest.name == "license":
                self.__add_license(src, dest)
                if not src:
                    # Initial installs require acceptance.
                    continue
                src_ma = src.attrs.get("must-accept", False)
                dest_ma = dest.attrs.get("must-accept", False)
                if (dest_ma and src_ma) and \
                    src.hash == dest.hash:
                    # If src action required acceptance,
                    # then license was already accepted
                    # before, and if the hashes are the
                    # same for the license payload, then
                    # it doesn't need to be accepted again.
                    self.set_license_status(dest.attrs["license"],
                                            accepted=True)

            # Keep a cache of dir actions with salvage-from attrs.
            # Since directories are installed in top-down order,
            # we need this list to make sure we salvage contents
            # as accurately as possible. For example, where:
            #
            #  /var/user gets salvaged to /var/.migrate/user
            #  and
            #  /var/user/myuser/.ssh to /var/.migrate/user/myuser/.ssh
            #
            # We must ensure that we don't try to salvage
            # var/user/myuser/.ssh when installing
            # /var/.migrate/user,
            # but instead wait till /var/.migrate/user/myuser/.ssh
            # is being installed, otherwise that content will
            # the salvaged to the wrong place.
            if (dest.name == "dir" and "salvage-from" in dest.attrs):
                for p in dest.attrlist("salvage-from"):
                    self.__salvage_actions[p] = dest