Exemplo n.º 1
0
def log_exception(e):
    log.Error('Exception [%s]:' % (e, ))
    f = StringIO.StringIO()
    traceback.print_exc(file=f)
    f.seek(0)
    for s in f.readlines():
        log.Error('| ' + s.rstrip())
    f.close()
Exemplo n.º 2
0
def command(login_required=True):
    """a decorator for handling authentication and exceptions"""
    def decorate(f):
        def wrapper(self, *args):
            if login_required and not self.sess.is_linked():
                log.FatalError("dpbx Cannot login: check your credentials",
                               log.ErrorCode.dpbx_nologin)
                return

            try:
                return f(self, *args)
            except TypeError, e:
                log_exception(e)
                log.FatalError('dpbx type error "%s"' % (e, ),
                               log.ErrorCode.backend_code_error)
            except rest.ErrorResponse, e:
                msg = e.user_error_msg or str(e)
                log.Error('dpbx error: %s' % (msg, ),
                          log.ErrorCode.backend_command_error)
                raise e
            except Exception, e:
                log_exception(e)
                log.Error('dpbx code error "%s"' % (e, ),
                          log.ErrorCode.backend_code_error)
                raise e
Exemplo n.º 3
0
 def token_updater(token):
     try:
         with open(self.OAUTH_TOKEN_PATH, u'w') as f:
             json.dump(token, f)
     except Exception as e:
         log.Error((u'Could not save the OAuth2 token to %s. '
                    u'This means you may need to do the OAuth2 '
                    u'authorization process again soon. '
                    u'Original error: %s' % (self.OAUTH_TOKEN_PATH, e)))
Exemplo n.º 4
0
 def token_updater(token):
     u"""Stores oauth2 token on disk"""
     try:
         with open(self.OAUTH_TOKEN_PATH, u'w') as f:
             json.dump(token, f)
     except Exception as err:
         log.Error(u'Could not save the OAuth2 token to %s. This means '
                   u'you may need to do the OAuth2 authorization '
                   u'process again soon. Original error: %s' %
                   (self.OAUTH_TOKEN_PATH, err))
Exemplo n.º 5
0
 def wrapper(self, *args):
     try:
         return f(self, *args)
     except ApiError as e:
         log_exception(e)
         raise BackendException(u'dpbx api error "%s"' % (e,))
     except Exception as e:
         log_exception(e)
         log.Error(u'dpbx code error "%s"' % (e,), log.ErrorCode.backend_code_error)
         raise
Exemplo n.º 6
0
    def get(self, remote_filename, local_path):
        u"""transfer remote_filename and the related .par2 file into
        a temp-dir. remote_filename will be renamed into local_path before
        finishing.

        If "par2 verify" detect an error transfer the Par2-volumes into the
        temp-dir and try to repair.
        """

        par2temp = local_path.get_temp_in_same_dir()
        par2temp.mkdir()
        local_path_temp = par2temp.append(remote_filename)

        self.wrapped_backend._get(remote_filename, local_path_temp)

        try:
            par2file = par2temp.append(remote_filename + b'.par2')
            self.wrapped_backend._get(par2file.get_filename(), par2file)

            par2verify = u'par2 v %s %s "%s"' % (
                self.common_options, util.fsdecode(par2file.get_canonical()),
                util.fsdecode(local_path_temp.get_canonical()))
            out, returncode = pexpect.run(par2verify, None, True)

            if returncode:
                log.Warn(u"File is corrupt. Try to repair %s" %
                         remote_filename)
                c = re.compile(u'%s\\.vol[\\d+]*\\.par2' %
                               remote_filename.decode())
                par2volumes = [
                    f for f in self.wrapped_backend._list()
                    if c.match(util.fsdecode(f))
                ]

                for filename in par2volumes:
                    file = par2temp.append(filename)
                    self.wrapped_backend._get(filename, file)

                par2repair = u'par2 r %s %s "%s"' % (
                    self.common_options, util.fsdecode(
                        par2file.get_canonical()),
                    util.fsdecode(local_path_temp.get_canonical()))
                out, returncode = pexpect.run(par2repair, None, True)

                if returncode:
                    log.Error(u"Failed to repair %s" % remote_filename)
                else:
                    log.Warn(u"Repair successful %s" % remote_filename)
        except BackendException:
            # par2 file not available
            pass
        finally:
            local_path_temp.rename(local_path)
            par2temp.deltree()
Exemplo n.º 7
0
def release_lockfile():
    if config.lockfile:
        log.Debug(_(u"Releasing lockfile %s") % config.lockpath)
        try:
            config.lockfile.release()
            config.lockfile = None
            os.remove(config.lockpath)
            config.lockpath = u""
        except Exception as e:
            log.Error(u"Could not release lockfile: %s" % str(e))
            pass
    def list_filenames_in_bucket(self):
        import oss2
        filename_list = []
        for item in oss2.ObjectIterator(self.bucket, prefix=self.key_prefix):
            try:
                filename = item.key.replace(self.key_prefix, '', 1)
                filename_list.append(filename)
                log.Debug("Listed %s/%s" % (self.straight_url, filename))
            except AttributeError:
                log.Error("List AttributeError")

        return filename_list
Exemplo n.º 9
0
        def wrapper(self, *args):
            if login_required and not self.sess.is_linked():
                raise BackendException(
                    "dpbx Cannot login: check your credentials",
                    log.ErrorCode.dpbx_nologin)
                return

            try:
                return f(self, *args)
            except TypeError as e:
                log_exception(e)
                raise BackendException('dpbx type error "%s"' % (e, ))
            except rest.ErrorResponse as e:
                msg = e.user_error_msg or util.uexc(e)
                log.Error('dpbx error: %s' % (msg, ),
                          log.ErrorCode.backend_command_error)
                raise e
            except Exception as e:
                log_exception(e)
                log.Error('dpbx code error "%s"' % (e, ),
                          log.ErrorCode.backend_code_error)
                raise e
Exemplo n.º 10
0
 def get_remote_manifest(self):
     """
     Return manifest by reading remote manifest on backend
     """
     assert self.remote_manifest_name
     try:
         manifest_buffer = self.backend.get_data(self.remote_manifest_name)
     except GPGError as message:
         log.Error(_("Error processing remote manifest (%s): %s") %
                   (util.ufn(self.remote_manifest_name), util.uexc(message)))
         return None
     log.Info(_("Processing remote manifest %s (%s)") % (
         util.ufn(self.remote_manifest_name), len(manifest_buffer)))
     return manifest.Manifest().from_string(manifest_buffer)
Exemplo n.º 11
0
    def transfer(self, method, source_path, remote_filename):
        u"""create Par2 files and transfer the given file and the Par2 files
        with the wrapped backend.

        Par2 must run on the real filename or it would restore the
        temp-filename later on. So first of all create a tempdir and symlink
        the soure_path with remote_filename into this.
        """
        par2temp = source_path.get_temp_in_same_dir()
        par2temp.mkdir()
        source_symlink = par2temp.append(remote_filename)
        source_target = source_path.get_canonical()
        if not os.path.isabs(source_target):
            source_target = os.path.join(util.fsencode(os.getcwd()),
                                         source_target)
        os.symlink(source_target, source_symlink.get_canonical())
        source_symlink.setdata()

        log.Info(u"Create Par2 recovery files")
        par2create = u'par2 c -r%d -n%d %s "%s"' % (
            self.redundancy, self.volumes, self.common_options,
            util.fsdecode(source_symlink.get_canonical()))
        out, returncode = pexpect.run(par2create, None, True)

        if returncode:
            log.Warn(
                u"Failed to create par2 file with requested options, retrying with -n1"
            )
            par2create = u'par2 c -r%d -n1 %s "%s"' % (
                self.redundancy, self.common_options,
                util.fsdecode(source_symlink.get_canonical()))
            out, returncode = pexpect.run(par2create, None, True)
            if not returncode:
                log.Warn(u"Successfully created par2 file with -n1")

        source_symlink.delete()
        files_to_transfer = []
        if not returncode:
            for file in par2temp.listdir():
                files_to_transfer.append(par2temp.append(file))
        else:
            log.Error(u"FAILED to create par2 file with returncode %d" %
                      returncode)

        method(source_path, remote_filename)
        for file in files_to_transfer:
            method(file, file.get_filename())

        par2temp.deltree()
Exemplo n.º 12
0
    def from_string(self, s):
        u"""
        Initialize self from string s, return self
        """
        def get_field(fieldname):
            u"""
            Return the value of a field by parsing s, or None if no field
            """
            if not isinstance(fieldname, bytes):
                fieldname = fieldname.encode()
            m = re.search(b"(^|\\n)%s\\s(.*?)\n" % fieldname, s, re.I)
            if not m:
                return None
            else:
                return Unquote(m.group(2))

        self.hostname = get_field(u"hostname")
        if self.hostname is not None:
            self.hostname = self.hostname.decode()
        self.local_dirname = get_field(u"localdir")

        highest_vol = 0
        latest_vol = 0
        vi_regexp = re.compile(
            b"(?:^|\\n)(volume\\s.*(?:\\n.*)*?)(?=\\nvolume\\s|$)", re.I)
        vi_iterator = vi_regexp.finditer(s)
        for match in vi_iterator:
            vi = VolumeInfo().from_string(match.group(1))
            self.add_volume_info(vi)
            latest_vol = vi.volume_number
            highest_vol = max(highest_vol, latest_vol)
            log.Debug(_(u"Found manifest volume %s") % latest_vol)
        # If we restarted after losing some remote volumes, the highest volume
        # seen may be higher than the last volume recorded.  That is, the
        # manifest could contain "vol1, vol2, vol3, vol2."  If so, we don't
        # want to keep vol3's info.
        for i in range(latest_vol + 1, highest_vol + 1):
            self.del_volume_info(i)
        log.Info(_(u"Found %s volumes in manifest") % latest_vol)

        # Get file changed list - not needed if --file-changed and
        # --show-changes-in-set are not present
        filecount = 0
        if config.file_changed is not None or config.show_changes_in_set is not None:
            filelist_regexp = re.compile(
                b"(^|\\n)filelist\\s([0-9]+)\\n(.*?)(\\nvolume\\s|$)",
                re.I | re.S)
            match = filelist_regexp.search(s)
            if match:
                filecount = int(match.group(2))
            if filecount > 0:

                def parse_fileinfo(line):
                    fileinfo = line.strip().split()
                    return (fileinfo[0], b''.join(fileinfo[1:]))

                self.files_changed = list(
                    map(parse_fileinfo,
                        match.group(3).split(b'\n')))

            if filecount != len(self.files_changed):
                log.Error(
                    _(u"Manifest file '%s' is corrupt: File count says %d, File list contains %d"
                      % (self.fh.base if self.fh else u"", filecount,
                         len(self.files_changed))))
                self.corrupt_filelist = True

        return self
Exemplo n.º 13
0
    def initialize_oauth2_session(self):
        def token_updater(token):
            try:
                with open(self.OAUTH_TOKEN_PATH, u'w') as f:
                    json.dump(token, f)
            except Exception as e:
                log.Error((u'Could not save the OAuth2 token to %s. '
                           u'This means you may need to do the OAuth2 '
                           u'authorization process again soon. '
                           u'Original error: %s' % (self.OAUTH_TOKEN_PATH, e)))

        token = None
        try:
            with open(self.OAUTH_TOKEN_PATH) as f:
                token = json.load(f)
        except IOError as e:
            log.Error(
                (u'Could not load OAuth2 token. '
                 u'Trying to create a new one. (original error: %s)' % e))

        self.http_client = OAuth2Session(self.CLIENT_ID,
                                         scope=self.OAUTH_SCOPE,
                                         redirect_uri=self.OAUTH_REDIRECT_URI,
                                         token=token,
                                         auto_refresh_kwargs={
                                             u'client_id': self.CLIENT_ID,
                                         },
                                         auto_refresh_url=self.OAUTH_TOKEN_URI,
                                         token_updater=token_updater)

        # We have to refresh token manually because it's not working "under the covers"
        if token is not None:
            self.http_client.refresh_token(self.OAUTH_TOKEN_URI)

        # Send a request to make sure the token is valid (or could at least be
        # refreshed successfully, which will happen under the covers). In case
        # this request fails, the provided token was too old (i.e. expired),
        # and we need to get a new token.
        user_info_response = self.http_client.get(self.API_URI + u'me')
        if user_info_response.status_code != requests.codes.ok:
            token = None

        if token is None:
            if not sys.stdout.isatty() or not sys.stdin.isatty():
                log.FatalError(
                    (u'The OAuth2 token could not be loaded from %s '
                     u'and you are not running duplicity '
                     u'interactively, so duplicity cannot possibly '
                     u'access OneDrive.' % self.OAUTH_TOKEN_PATH))
            authorization_url, state = self.http_client.authorization_url(
                self.OAUTH_AUTHORIZE_URI, display=u'touch')

            print()
            print(u'In order to authorize duplicity to access your OneDrive, '
                  u'please open %s in a browser and copy the URL of the blank '
                  u'page the dialog leads to.' % authorization_url)
            print()

            redirected_to = input(u'URL of the blank page: ').strip()

            token = self.http_client.fetch_token(
                self.OAUTH_TOKEN_URI, authorization_response=redirected_to)

            user_info_response = self.http_client.get(self.API_URI + u'me')
            user_info_response.raise_for_status()

            try:
                with open(self.OAUTH_TOKEN_PATH, u'w') as f:
                    json.dump(token, f)
            except Exception as e:
                log.Error(
                    (u'Could not save the OAuth2 token to %s. '
                     u'This means you need to do the OAuth2 authorization '
                     u'process on every start of duplicity. '
                     u'Original error: %s' % (self.OAUTH_TOKEN_PATH, e)))