Esempio n. 1
0
def stop_bitcoin_qt():
    '''
        Stop bitcoin_qt and determine if it ended properly.

        >>> init_database()
        >>> stop_bitcoin_qt()
    '''
    seconds = 0
    while (bitcoin_utils.is_bitcoin_qt_running() and seconds < 60):
        try:
            send_bitcoin_cli_cmd('stop')
            sleep(5)
            seconds += 5
        except:
            pass

    # use brute force if necessary
    if bitcoin_utils.is_bitcoin_qt_running():
        bin_dir = os.path.join(virtualenv_dir(), 'bin')
        args = [os.path.join(bin_dir, 'killmatch'), bitcoin_utils.bitcoin_qt()]
        command.run(*args).stdout

    # give it a little more time to settle down
    sleep(5)

    log(f'bitcoin-qt running: {bitcoin_utils.is_bitcoin_qt_running()}')
Esempio n. 2
0
    def finish_build(self):
        ''' Finish build with finally links.'''

        virtual_bin_dir = os.path.join(self.virtualenv_dir(), 'bin')
        if not os.path.exists(os.path.join(virtual_bin_dir, 'uwsgi')):
            command_args = ['ln', '-s', '/usr/bin/uwsgi', virtual_bin_dir]
            run(*command_args)
Esempio n. 3
0
def move(source, dest, owner=None, group=None, perms=None):
    ''' Move source to dest.

        move() tries to generally follow the behavior of the
        'mv --force' command.

        move() creates any missing parent dirs of dest.

        If dest is a dir, source is copied into dest.

        Otherwise, source will overwrite any existing dest.

        >>> import os.path, tempfile

        >>> def temp_filename(dir=None):
        ...     if dir is None:
        ...         dir = test_dir
        ...     handle, path = tempfile.mkstemp(dir=dir)
        ...     # we don't need the handle
        ...     os.close(handle)
        ...     return path
        >>>
        >>> test_dir = tempfile.mkdtemp()
        >>>
        >>> # test move to dir
        >>> source = temp_filename()
        >>> dest_dir = tempfile.mkdtemp(dir=test_dir)
        >>> move(source, dest_dir)
        >>> assert not os.path.exists(source)
        >>> basename = os.path.basename(source)
        >>> assert os.path.exists(os.path.join(dest_dir, basename))
        >>>
        >>> # test move to new filename
        >>> source = temp_filename()
        >>> dest_filename = temp_filename(dir=test_dir)
        >>> move(source, dest_filename)
        >>>
        >>> # test move to existing filename
        >>> DATA = 'data'
        >>> source = temp_filename()
        >>> dest_filename = temp_filename()
        >>> with open(source, 'w') as sourcefile:
        ...     sourcefile.write(DATA)
        4
        >>> move(source, dest_filename)
        >>> assert not os.path.exists(source)
        >>> assert os.path.exists(dest_filename)
        >>> with open(dest_filename) as destfile:
        ...     assert DATA == destfile.read()
        >>>
        >>> # clean up
        >>> result = run(*['rm', '--force', '--recursive', test_dir])
        >>> assert result.returncode == 0
    '''

    parent_dir = os.path.dirname(dest)
    if not os.path.exists(parent_dir):
        makedir(parent_dir, owner=owner, group=None, perms=None)
    run(*['mv', '--force', source, dest])
    set_attributes(dest, owner, group, perms, recursive=True)
Esempio n. 4
0
def say(message):
    ''' Speak a message.

        Runs a "say" program, passing the message on the command line.
        Because most systems are not set up for speech, it is not an
        error if the "say" program is missing or fails.

        It is often easy to add a "say" program to a system. For example,
        a linux system using festival for speech can use a one line script:
            festival --batch "(SayText \"$*\")"

        Depending on the underlying 'say' command's implementation, say()
        probably does not work unless user is in the 'audio' group.

        >>> say('test say')
        '''

    enabled = True

    if enabled:
        try:
            from denova.os import command
            # the words are unintelligible, and usually all we want is to know something happened
            # message = 'tick' # just a sound #DEBUG
            # os.system passes successive lines to sh
            message = message.split('\n')[0]
            command.run('say', *message)
        except:  # 'bare except' because it catches more than "except Exception"
            pass
Esempio n. 5
0
def main():
    '''
        Systemd shutdown for blockchain_backup.

        >>> main()
        not running
    '''

    if utils.is_bitcoin_core_running():
        log.debug('bitcoin core is running')
        bin_dir = utils.get_bitcoin_bin_dir()
        if bin_dir:
            bitcoin_cli = os.path.join(bin_dir, utils.bitcoin_cli())
            log.debug('stop bitcoin core')
            run(bitcoin_cli, 'stop')

            # bitcoin core returns immediatly after 'stop'
            # but takes a while to shut down
            time.sleep(1)
            if utils.is_bitcoin_core_running():
                log.debug('waiting for bitcoin core to stop')
                while utils.is_bitcoin_core_running():
                    time.sleep(1)

            log.debug('stopped bitcoin core')
            print('stopped bitcoin core')
        else:
            log.debug('unable to find bitcoin core bin dir')
            print('no bitcoin core bin dir')
    else:
        log.debug('bitcoin core is not running')
        print('not running')
Esempio n. 6
0
def start_gunicorn_server_for_django(bin_dir, python_cmd):
    ''' Start the gunicorn server for django connections.'''

    log('starting django webserver')

    try:
        GUNICORN_CONFIG_PATH = os.path.abspath(os.path.join(CURRENT_DIR, 'gunicorn.conf.py'))

        log('starting gunicorn for django connections')
        gunicorn_cmd = os.path.join(bin_dir, 'gunicorn')
        args = []
        args.append(python_cmd)
        args.append(gunicorn_cmd)
        args.append('--config')
        args.append(GUNICORN_CONFIG_PATH)
        args.append(f'{TOP_LEVEL_DOMAIN}.wsgi_django:application')
        try:
            run(*args)
            log(f'started gunicorn for {TOP_LEVEL_DOMAIN}')
        except CalledProcessError as scpe:
            log('gunicorn threw a CalledProcessError while starting')
            log(scpe.stderr)
            raise
        except Exception as e:
            log('gunicorn threw an unexpected exception while starting')
            log(e)
            raise

    except: # 'bare except' because it catches more than "except Exception"
        error = format_exc()
        log(error)
        sys.exit(error)
Esempio n. 7
0
    def verify_failure(self, description, *test_args):
        # this test should fail

        log(f'Test {description}\n\t')

        with cd(TMP_DIR):

            try:
                args = ['python3', SAFEGET_APP
                        ] + list(test_args) + ['--verbose']
                log(f'{description} args: {args}')

                run(*args)

            except CalledProcessError as cpe:
                log(cpe)
                log('Passed: Test of failure condition failed as expected')

            except Exception:
                log('Error in test')
                self.assertFalse()

            else:
                log('Failed: Test of failure condition incorrectly succeeded')
                self.assertFalse()
Esempio n. 8
0
def start_uwsgi_server_for_socketio(bin_dir):
    ''' Start the uwsgi server for socketio connections.'''

    log('starting uwsgi for socketio connections')
    uwsgi_cmd = os.path.join(bin_dir, 'uwsgi')
    if not os.path.exists(uwsgi_cmd):
        uwsgi_cmd = 'uwsgi'
    ini_path = os.path.abspath(
        os.path.join(PROJECT_PATH, 'config/uwsgi_socketio.ini'))
    args = [uwsgi_cmd, ini_path]
    print(f'args: {args}')

    try:
        run(*args)
        log('uwsgi socketio server started')
    except CalledProcessError as scpe:
        log('uwsgi socketio server threw a CalledProcessError')
        log(scpe.stderr)
        raise
    except Exception as e:
        log('uwsgi socketio server threw an unexpected exception')
        log(e)
        raise
    except:  # 'bare except' because it catches more than "except Exception"
        log('uwsgi socketio server threw an unexpected error')
        raise
    log('socketio server started')
Esempio n. 9
0
def stop_bitcoind():
    ''' Stop bitcoind if it's running. '''

    log('stopping bitcoind')

    bin_dir = os.path.join(virtualenv_dir(), 'bin')

    try:
        SHUTDOWN_PATH = os.path.abspath(os.path.join(CURRENT_DIR, 'bitcoin_shutdown.py'))

        python_cmd = os.path.join(bin_dir, 'python')
        args = []
        args.append(python_cmd)
        args.append(SHUTDOWN_PATH)
        try:
            run(*args)
        except CalledProcessError as scpe:
            log(scpe.stderr)
        except Exception as e:
            log(e)

    except: # 'bare except' because it catches more than "except Exception"
        error = format_exc()
        log(error)

    log('bitcoind stopped')
Esempio n. 10
0
def remove(path):
    ''' Remove the path.

        If path is a dir, empty it first by rsyncing an empty dir to the
        path. With a large directory this is much faster than rm or
        shutil.rmtree().

        It is not an error if the path does not exist.

        If path is a link, only remove the link, not the target.

        If path is a mount, raise ValueError.
    '''

    global empty_dir

    if os.path.exists(path):

        if empty_dir is None:
            empty_dir = tempfile.mkdtemp(prefix='denova.os.fs.empty.')

        if os.path.ismount(path):
            raise ValueError(f'path is mount point: {path}')

        elif os.path.islink(path) or os.path.isfile(path):
            run(*['rm', '--force', path])

        else:
            assert os.path.isdir(path)

            run(*['rm', '--force', '--recursive', path])

    assert not os.path.exists(path), f'could not remove {path}'
Esempio n. 11
0
def pip_install_pkgs(pip3_command):
    ''' Pip install packages needed during setup. '''

    # pip install without input and ignore if it already exists
    run(*[
        pip3_command, 'install', 'pexpect', '--no-input', '--exists-action',
        'i'
    ])
    def update(self):
        '''
            Automatically update the blockchain.

            Returns:
                True if successful.
                False if any errors.
        '''
        ok = True

        try:
            bitcoind_process, bitcoind_pid = core_utils.start_bitcoind(self.bin_dir, self.data_dir)
            if bitcoind_process is None and bitcoind_pid is None:
                self.print_on_same_line('Error starting bitcoind')
                ok = False
            else:
                self.wait_while_updating(bitcoind_process, secs_to_wait=self.WAIT_SECONDS)

                ok, error_message = core_utils.stop_bitcoind(
                  bitcoind_process, bitcoind_pid, self.bin_dir, self.data_dir)

        except BitcoinException as be:
            ok = False
            error_message = str(be)
            log(error_message)

        except KeyboardInterrupt:

            self.interrupted = True
            log('^C typed; interrupting update')

            if core_utils.is_bitcoind_running():
                print('^C typed; Stopping update. Please wait...')

                program = os.path.join(PROJECT_PATH, 'config', 'bitcoin_shutdown.py')
                try:
                    command.run('python3', program)
                except Exception as exc:
                    log(exc)
                    raise

                ok = False

            self.interrupted = False

        except: # 'bare except' because it catches more than "except Exception"
            log(format_exc())

            # sometimes bitcoin exits with a non-zero return code,
            # but it was still ok, so check the logs
            ok, error_message = core_utils.bitcoin_finished_ok(self.data_dir,
                                                               core_utils.is_bitcoind_running)

        if ok:
            self.print_on_same_line(f'Remaining blocks to update at {self.get_current_time()}: 0')
            self.print_on_same_line('Finished updating blockchain')

        return ok
Esempio n. 13
0
def mount(*args, **kwargs):
    ''' Convenience function for mount. '''

    try:
        all_args = ['mount']
        for arg in args:
            all_args.append(arg)
        run(*all_args, **kwargs)
    except Exception as exc:
        log.debug(exc)
        raise
Esempio n. 14
0
 def run(self):
     try:
         if DEBUG: log(f'in run kill pid: {self.killpid}')  # DEBUG
         #kill(self.killpid)
         run('killsafe', self.killpid)
     except Exception as e:
         # unclear why killsafe returns an error even though it
         # does successfully kill the job, but we'll just
         # ignore the error
         log(e)
         print(e)
Esempio n. 15
0
def stop():
    log('stopping django server')
    try:
        run('fuser', '--kill', f'{DJANGO_PORT}/tcp')
    except CalledProcessError as scpe:
        log('django server threw a CalledProcessError while stopping')
        log(scpe)
        run('killmatch', 'blockchain-backup-django-server')
    except Exception as e:
        log('django servers threw an unexpected exception while stopping')
        log(e)
    log('django server stopped')
Esempio n. 16
0
def different(file1, file2):
    ''' Returns whether the files are different. '''

    # diff succeeds if there is a difference, and fails if no difference
    try:
        from denova.os import command
        command.run('diff', file1, file2, brief=True)
        different = False

    except CalledProcessError:
        different = True

    return different
Esempio n. 17
0
    def copy_service_file(self, filename):
        '''
            Copy service file to the config subdirectory.
        '''

        SERVICE_PATH = os.path.join('/etc/systemd/system', filename)
        if os.path.exists(SERVICE_PATH):
            try:
                command_args = ['cp', SERVICE_PATH, self.current_dir]
                run(*command_args)
            except:
                # if this fails, that's ok
                pass
Esempio n. 18
0
        def make_exec_and_link(virtual_bin_dir, path, to_path=None):
            ''' Make the path executable and link to virtualenv bin. '''

            command_args = ['chmod', '+x', path]
            run(*command_args)
            if to_path:
                command_args = [
                    'ln', '-s', path,
                    os.path.join(virtual_bin_dir, to_path)
                ]
            else:
                command_args = ['ln', '-s', path, virtual_bin_dir]
            run(*command_args)
Esempio n. 19
0
    def interrupt_restore(self):
        '''
            User wants the restoration interrupted.
            This is not recommended because it almost
            always leaves the blockchain in unusable shape.

            >>> from blockchain_backup.bitcoin.tests import utils as test_utils
            >>> test_utils.init_database()
            >>> restore_dir = os.path.join(gettempdir(), 'bitcoin/data/testnet3/backups/level1')
            >>> restore_task = RestoreTask(restore_dir)
            >>> restore_task.manager = BitcoinManager(restore_task.log_name)
            >>> test_utils.start_fake_restore()
            >>> restore_task.interrupt_restore()
            True
        '''

        max_secs = 3
        seconds = 0

        try:
            bin_dir = os.path.join(virtualenv_dir(), 'bin')
            args = [
                os.path.join(bin_dir, 'killmatch'), constants.RESTORE_PROGRAM
            ]
            args = [
                os.path.join('/usr/local/bin', 'killmatch'),
                constants.RESTORE_PROGRAM
            ]
            self.log(f'args: {args}')

            attempts = 0
            while bitcoin_utils.is_restore_running() and attempts < 5:
                command.run(*args)
                if bitcoin_utils.is_restore_running():
                    sleep(3)
                    attempts += 1
        except CalledProcessError as cpe:
            self.log(cpe)
            self.log(format_exc())

        # a new page was displayed so give socketio time to connect
        while seconds < max_secs:
            self.manager.update_header(self.STOPPED_RESTORE)
            self.manager.update_subnotice(self.STOP_RESTORE_NOT_COMPLETE)
            self.manager.notify_done()

            sleep(1)
            seconds += 1

        # return value is for testing purposes only
        return not bitcoin_utils.is_restore_running()
Esempio n. 20
0
def stop():

    log('stopping socketio server')
    try:
        run('fuser', '--kill', f'{SOCKETIO_PORT}/tcp')
    except CalledProcessError as cpe:
        log('socketio server threw a CalledProcessError')
        log(cpe)
        try:
            run('killmatch', 'blockchain-backup-socketio-server')
        except:  # 'bare except' because it catches more than "except Exception"
            log(format_exc())
    except Exception as e:
        log('socketio server threw an unexpected exception')
        log(e)
    log('socketio server stopped')
Esempio n. 21
0
def list_block_devices():
    ''' List block devices, i.e. drives and partitions

        >>> blocks = list_block_devices()
    '''

    blocks = []
    lsblk_out = run('lsblk', '--list').stdout
    """ Example output::
            NAME MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
            sda    8:0    0 698.7G  0 disk
            sda1   8:1    0 694.8G  0 part /
            sda2   8:2    0     1K  0 part
            sda5   8:5    0   3.9G  0 part [SWAP]
            sdb    8:16   1 970.5M  0 disk
            sdb1   8:17   1   958M  0 part
            sr0   11:0    1  1024M  0 rom
    """
    lines = lsblk_out.split('\n')
    for line in lines:
        if line.startswith('s'):
            name = line.split()[0]
            blocks.append(name)

    return blocks
Esempio n. 22
0
def import_module(name):
    '''
        Import with debugging

        >>> module_str = str(import_module("denova.os.user"))
        >>> module_str.startswith("<module 'denova.os.user' from ")
        True
        >>> module_str.endswith("denova/os/user.py'>")
        True
    '''

    try:
        log(f'import_module({name})')  #DEBUG
        module = importlib.import_module(name)
        log(f'import_module() result: {module}')  #DEBUG
    except ImportError as imp_error:
        log(f'unable to import {name}')
        log('ImportError: ' + str(imp_error))
        msg = f'could not import {name}'
        log(msg)
        # find out why
        from denova.os import command
        log(command.run(['python3', '-c', f'import {name}']).stderr)
        raise ImportError(msg)
    return module
Esempio n. 23
0
def program_status(program_name):
    '''
        Returns a list of matching raw lines from "ps" if program is running.
        If no lines match, returns an empty list.
        Ignores any program_name that is defunct.

        >>> lines = program_status('python3')
        >>> lines == []
        False
    '''
    PS_ARGS = ['-eo', 'pid,args']

    lines = []
    try:
        raw = run('ps', *PS_ARGS)
        raw_lines = raw.stdout.strip().split('\n')
        log(f'raw lines:\n{raw_lines}')

        for line in raw_lines:
            line = str(line).strip()
            # apparent the leading space matters
            if program_name in line and ' <defunct>' not in line:
                lines.append(line)
    except:  # 'bare except' because it catches more than "except Exception"
        log(format_exc())

    return lines
Esempio n. 24
0
def stop():
    log('stopping django server')

    # make sure bitcoind is shutdown before we shut down this server
    stop_bitcoind()

    try:
        run(*['fuser', '--kill', f'{DJANGO_PORT}/tcp'])
    except CalledProcessError as scpe:
        log('django server threw a CalledProcessError while stopping')
        log(scpe)
        run(*['killmatch', 'blockchain-backup-server'])
    except Exception as e:
        log('django servers threw an unexpected exception while stopping')
        log(e)
    log('django server stopped')
Esempio n. 25
0
def devices():
    ''' Return list of devices that may have filesystems. '''

    # block devices may have filesystems
    raw_output = run(*['lsblk', '--noheadings', '--list', '--paths', '--output=NAME']).stdout.decode()
    devices = raw_output.strip().split('\n')
    return devices
Esempio n. 26
0
def send_bitcoin_cli_cmd(arg):
    '''
        Send a command via bitcoin-cli.

        >>> init_database()
        >>> start_bitcoind()
        >>> block_count = send_bitcoin_cli_cmd('getblockcount')
        >>> stop_bitcoind()
    '''

    bin_dir, data_dir = preferences.get_bitcoin_dirs()

    command_args = []
    command_args.append(os.path.join(bin_dir, bitcoin_utils.bitcoin_cli()))

    use_test_net = '-testnet' in preferences.get_extra_args()
    if use_test_net:
        command_args.append('-testnet')

    if data_dir is not None:
        data_dir = bitcoin_utils.strip_testnet_from_data_dir(data_dir=data_dir)
        command_args.append(f'-datadir={data_dir}')

    command_args.append(arg)
    log(f'running: {command_args}')

    try:
        result = command.run(*command_args).stdout
        log(f'result: {result}')
    except CalledProcessError as cpe:
        result = None

    return result
Esempio n. 27
0
    def build(self):

        os.chdir(self.parent_dirname())
        self.init_virtualenv()

        if self.virtualenv_dir_exists():
            self.log(f'building virtual environment in {self.parent_dirname()}')
            os.chdir(self.virtualenv_dir())

            # activate the virtualenv
            with venv(dirname=self.virtualenv_dir()):

                # set up a link to the python lib for simplier config
                dirname = None
                entries = os.scandir(os.path.join(self.virtualenv_dir(), 'lib'))
                for entry in entries:
                    if entry.name.startswith('python3'):
                        dirname = entry.name
                        break
                if dirname is None:
                    dirname = 'python3.7'

                os.chdir('lib')
                run('ln', '-s', dirname, 'python')

                self.report('   installing requirements')
                with open(self.get_requirements()) as f:
                    for line in f.readlines():
                        if line.strip():
                            app = line.strip()
                            self.report(f'     {app}')
                            try:
                                run('pip3', 'install', app)
                            except CalledProcessError as cpe:
                                self.log(format_exc())
                                if cpe.stdout: self.log(f'stdout: {cpe.stdout}')
                                if cpe.stderr: self.log(f'stderr: {cpe.stderr}')
                                sys.exit(
                                  f'{cpe.stderr}. For more details see {self.log.pathname}')

            self.log('   linking packages')
            self.link_packages(os.path.join(self.virtualenv_dir(), 'lib', 'python', 'site-packages'))

            self.finish_build()
            self.log('   virtual environment built')
        else:
            self.log(f'!!!Error: Unable to create {self.virtualenv_dir()}')
Esempio n. 28
0
def config_logs(project_dir, primary_user):
    ''' Configure the log directory and logging server. '''
    def config_user_log_dir(user_log_dir, user):
        if not os.path.exists(user_log_dir):
            os.mkdir(user_log_dir)

        run(*['chown', f'{user}:{user}', user_log_dir])
        run(*['chmod', 'u+rwx,g-rwx,o-rwx', user_log_dir])

    MAIN_LOG_DIR = os.path.join(os.sep, 'var', 'local', 'log')
    if not os.path.exists(MAIN_LOG_DIR):
        os.makedirs(MAIN_LOG_DIR)
    run(*['chmod', 'u+rwx,g+rx,o+rx', MAIN_LOG_DIR])

    config_user_log_dir(os.path.join(MAIN_LOG_DIR, 'root'), 'root')
    config_user_log_dir(os.path.join(MAIN_LOG_DIR, 'www-data'), 'www-data')
    config_user_log_dir(os.path.join(MAIN_LOG_DIR, primary_user), primary_user)
Esempio n. 29
0
def clear_user_logs(user):
    ''' Clear all logs created by this module for the user.

        The caller must have the correct file permissions.
    '''

    logdir = os.path.join(BASE_LOG_DIR, user)
    if os.listdir(logdir):
        run('rm', f'{logdir}/*')

    # if denova.python.log.DEBUGGING is True, then denova.python.log creates alt logs
    alt_log = f'/tmp/_log.{user}.log'
    if os.path.exists(alt_log):
        os.remove(alt_log)

    default_log = f'/tmp/python.default.{user}.log'
    if os.path.exists(default_log):
        os.remove(default_log)
Esempio n. 30
0
def chgrp(group, path, recursive=False):
    ''' Change group of path.

        'group' can be the group name, gid as an int, or gid as a string.

        Log and reraise any exception.
    '''

    try:
        if recursive:
            run(*['chgrp', '--recursive', group, path])
        else:
            run(*['chgrp', group, path])
        #log.debug(f'chgrp(group={group}, path=={path})')
    except CalledProcessError as cpe:
        # import delayed to avoid infinite recursion
        from denova.os.user import whoami

        log.error(f'unable to chgrp: user={whoami()}, group={group}, path={path}')
        log.error(cpe)
        raise

    # verify. after we have higher confidence, move this into doctests
    if type(group) is str and ':' in group:
        owner, group = group.split(':')
    else:
        owner = None
    if owner is not None:
        try:
            uid = int(owner)
        except ValueError:
            # import delayed to avoid infinite recursion
            from denova.os.user import getuid

            uid = getuid(owner)
        assert getuid(path) == uid, f'uid set to {uid} but is {getuid(path)}'
    try:
        gid = int(group)
    except ValueError:
        # import delayed to avoid infinite recursion
        from denova.os.user import getuid

        gid = getgid(group)
    assert getgid(path) == gid, f'gid set to {gid} but is {getgid(path)}'