Esempio n. 1
0
    def _action(self, info):
        action = info["action"]
        filename = info["filename"]
        fullpath = path.join(self.installpath, filename)

        # verify file integrity and attempt to repair if corrupted
        if action == "verify":
            log.info("Action: verify {0}".format(filename))
            hash = info["sha1-before"]
            if not sha1(fullpath) == hash:
                if "full-uri" in info:
                    fullformat = None
                    if "full-format" in info:
                        fullformat = info["full-format"]

                    self._backup(filename)
                    log.info("Extract replacement file from {0}".format(info["full-uri"]))
                    with URI(info["full-uri"], package=self.package, format=fullformat,
                             target=fullpath):
                        if not sha1(fullpath) == hash:
                            raise Exception("Integrity check and repair failed")

                else:
                    raise Exception("Integrity check failed with no repair")

        # create a new file and verify integrity
        elif action == "create":
            log.info("Action: create {0}".format(filename))
            hash = info["sha1-after"]
            if "full-uri" in info:
                fullformat = None
                if "full-format" in info:
                    fullformat = info["full-format"]

                log.info("Extract new file from {0}".format(info["full-uri"]))
                with URI(info["full-uri"], package=self.package, format=fullformat,
                         target=fullpath):
                    if not sha1(fullpath) == hash:
                        raise Exception("Created file failed integrity check")

            else:
                raise Exception("Create action has no URI")

        # replace file and verify replacement integrity
        elif action == "replace":
            log.info("Action: replace {0}".format(filename))
            hash = info["sha1-after"]
            if "full-uri" in info:
                fullformat = None
                if "full-format" in info:
                    fullformat = info["full-format"]

                self._backup(filename)
                log.info("Extract replacement file from {0}".format(info["full-uri"]))
                with URI(info["full-uri"], package=self.package, format=fullformat,
                         target=fullpath):
                    if not sha1(fullpath) == hash:
                        raise Exception("Replacement file failed integrity check")

            else:
                raise Exception("Replacement action has no URI")

        # delete a file with little recourse
        elif action == "delete":
            log.info("Action: delete {0}".format(filename))
            self._backup(filename)

        # intentional exception to test rollbacks
        elif action == "exception":
            log.warning("Action: exception")
            raise Exception("Intentional exception raised")

        # /shrug
        else:
            raise Exception("Unsupported action %s" % (action))
Esempio n. 2
0
    def apply(self, installpath, backuppath=None):
        """
        Apply the manifest against the given installation path.
        """

        self.installpath = installpath
        manifest = self.manifest

        # fetch and verify package
        if "package-uri" in manifest:
            packageuri = URI(manifest["package-uri"])
            packagename = path.basename(packageuri["path"])
            packagepath = path.join(tempfile.gettempdir(), packagename)

            packageformat = None
            if "package-format" in manifest:
                packageformat = manifest["package-format"]

            # download package file
            log.info("Fetching update package from {0}".format(packageuri.uri))
            packageuri.fetch(packagepath)
            packageuri.close()

            # integrity check
            if "package-sha1" in manifest:
                packagesha1 = sha1(packagepath)
                if not packagesha1 == manifest["package-sha1"]:
                    raise Exception("Package integrity check failed")

            self.package = Package(packagepath, packageformat)

        # create spot for backup files
        if backuppath is None:
            self.backuppath = tempfile.mkdtemp(prefix="update_")
        else:
            self.backuppath = backuppath

        if not path.isdir(self.backuppath):
            log.debug("Backup path {0} does not exist; creating".format(self.backuppath))
            os.mkdir(self.backuppath)

        # start applying actions
        try:
            for info in manifest.actions:
                self._action(info)

        # handle update errors by rolling back
        except Exception as err:
            log.exception("Exception eaten; beginning rollback")

            for root, dirs, files in os.walk(self.backuppath):
                relpath = path.relpath(root, self.backuppath)

                if relpath == ".":
                    relpath = ""

                for filename in files:
                    filepath = path.join(relpath, filename)

                    log.info("Rolling back file %s" % (filepath))

                    self._restore(filepath)

            log.info("Rollback completed; raising exception")
            raise

        # clean up
        finally:
            self.cleanup = False
            shutil.rmtree(self.backuppath, onerror=self._onerror)

            self.package.close()
            os.remove(packagepath)

            if self.cleanup:
                return self.backuppath
Esempio n. 3
0
    def fetch(self, target=None):
        parse = self.parse

        # local file
        if parse.scheme == "file":
            self.handle = File(parse.path, "r", format=self.format)

            if target:
                self.handle.decompress(target)
                self.handle.close()
                self.handle = File(target, "r")

        # package file
        elif parse.scheme == "package":
            if self.package is None:
                raise Exception("No package specified")

            filename = parse.path.lstrip("/")
            self.handle = self.package.open(filename, "r", format=self.format)

            if target:
                self.handle.decompress(target)
                self.handle.close()
                self.handle = File(target, "r")

        # remote http resource
        elif parse.scheme in ("http", "https"):
            failure = True
            tries = 0

            while failure:
                failure = False

                try:
                    if target:
                        target = path.normpath(target)
                        log.info("Downloading {0} to file {1}".format(self.uri, target))
                        downloadpath, headers = urllib.urlretrieve(self.uri)
                        self.handle = File(downloadpath, "r", format=self.format)
                        self.handle.decompress(target)
                        self.handle.close()
                        self.handle = File(target, "r")
                    else:
                        self.handle = urllib2.urlopen(self.uri)

                except:
                    failure = True
                    if tries < 3:
                        log.info("Problem retrieving URI, retry in 3 seconds...")
                        log.debug(traceback.format_exception(sys.exc_type,
                                                             sys.exc_value,
                                                             sys.exc_traceback))
                        time.sleep(3)

                    else:
                        log.info("Failed retrieving URI")
                        raise

                finally:
                    tries += 1

            return self.handle

        else:
            raise Exception("Unsupported URI scheme {0}".format(parse.scheme))

        return self.handle