Пример #1
0
    def __init__(self,
                 role,
                 name,
                 client_name,
                 client,
                 *,
                 type=None,
                 monitoring=None,
                 notification=None,
                 venv_path=None,
                 witness_id=None,
                 signing_key=None,
                 **kwargs):
        self.role = role
        if type is not None:
            self._type = type
        self.name = name
        self.witness_signing_key = None
        self.monitoring = to_list(monitoring)
        self.notification = to_list(notification)
        self.client_name = client_name
        data_dir = client.get('data_dir')
        if data_dir:
            data_dir = expanduser(data_dir)

            try:
                log.info('Loading RPC config for %s from %s (client = %s)' %
                         (self.name, data_dir, client_name))
                config = configparser.ConfigParser()
                config_str = '[bts]\n' + open(
                    expanduser(join(data_dir, 'config.ini'))).read()
                # config parser can't handle duplicate values, and we don't need seed nodes
                config_lines = [
                    l for l in config_str.splitlines()
                    if not l.startswith('seed-node')
                ]
                config.read_string('\n'.join(config_lines))
                rpc = {
                }  # FIXME: need it to get the rpc user and rpc password, if necessary
                try:
                    cfg_port = int(config['bts']['rpc-endpoint'].split(':')[1])
                except KeyError:
                    cfg_port = 0
                try:
                    if self.affiliation() == 'steem':
                        self.witness_signing_key = config['bts']['private-key']
                    else:
                        self.witness_signing_key = json.loads(
                            config['bts']['private-key'])[0]
                except KeyError:
                    self.witness_signing_key = None
                log.debug('signing key: {}'.format(self.witness_signing_key))

            except Exception as e:
                log.warning('Cannot read RPC config from %s' % data_dir)
                log.exception(e)
                rpc = {}
                cfg_port = None
        else:
            rpc = {}
            cfg_port = None

        self.witness_host = client.get('witness_host')
        self.witness_port = client.get('witness_port')
        self.witness_user = client.get('witness_user')
        self.witness_password = client.get('witness_password')
        self.wallet_host = client.get('wallet_host')
        self.wallet_port = client.get('wallet_port') or cfg_port or 0
        self.wallet_user = client.get('wallet_user')
        self.wallet_password = client.get('wallet_password')
        self.proxy_host = client.get('proxy_host')
        self.proxy_port = client.get('proxy_port')
        self.proxy_user = client.get('proxy_user')
        self.proxy_password = client.get('proxy_password')

        self.rpc_id = (self.wallet_host, self.wallet_port)
        self.ws_rpc_id = (self.witness_host, self.witness_port)
        self.venv_path = venv_path
        self.witness_id = witness_id
        self.witness_signing_key = signing_key or self.witness_signing_key

        # direct json-rpc call
        def direct_call(funcname, *args):
            # we want to avoid connecting to the client and block because
            # it is in a stopped state (eg: in gdb after having crashed)
            if self.is_localhost() and not bts_binary_running(self):
                raise RPCError(
                    'Connection aborted: {} binary does not seem to be running'
                    .format(self.type()))

            if self.proxy_host is not None and self.proxy_port is not None:
                return rpc_call(self.proxy_host,
                                self.proxy_port,
                                None,
                                None,
                                funcname,
                                *args,
                                rpc_args=dict(
                                    proxy_user=self.proxy_user,
                                    proxy_password=self.proxy_password,
                                    wallet_port=self.wallet_port))

            return rpc_call(self.wallet_host, self.wallet_port,
                            self.wallet_user, self.wallet_password, funcname,
                            *args)

        self._rpc_call = direct_call

        if core.config.get('profile', False):
            self._rpc_call = core.profile(self._rpc_call)

        self.opts = kwargs
        if self.opts:
            log.debug('Additional opts for node {} - {}'.format(
                self.name, self.opts))

        # get a special "smart" cache for slots as it is a very expensive call
        self._slot_cache = make_region().configure('dogpile.cache.memory')

        # caches for committee member and witness names
        self._witness_names = {}
        self._committee_member_names = {}
Пример #2
0
    def __init__(self, role, name, client_name, client, type=None,
                 monitoring=None, notification=None, venv_path=None,
                 witness_id=None, signing_key=None, **kwargs):
        self.role = role
        if type is not None:
            self._type = type
        self.name = name
        self.witness_signing_key = None
        self.monitoring = to_list(monitoring)
        self.notification = to_list(notification)
        self.client_name = client_name
        data_dir = client.get('data_dir')
        if data_dir:
            data_dir = expanduser(data_dir)

            try:
                log.info('Loading RPC config for %s from %s (run_env = %s)' % (self.name, data_dir, client_name))
                if is_graphene_based(client_name):
                    config = configparser.ConfigParser()
                    config_str = '[bts]\n' + open(expanduser(join(data_dir, 'config.ini'))).read()
                    # config parser can't handle duplicate values, and we don't need seed nodes
                    config_lines = [l for l in config_str.splitlines() if not l.startswith('seed-node')]
                    config.read_string('\n'.join(config_lines))
                    rpc = {}  # FIXME: need it to get the rpc user and rpc password, if necessary
                    try:
                        cfg_port = int(config['bts']['rpc-endpoint'].split(':')[1])
                    except KeyError:
                        cfg_port = 0
                    try:
                        if self.type() == 'steem':
                            self.witness_signing_key = config['bts']['private-key']
                        else:
                            self.witness_signing_key = json.loads(config['bts']['private-key'])[0]
                    except KeyError:
                        self.witness_signing_key = None
                    log.debug('signing key: {}'.format(self.witness_signing_key))
                else:
                    rpc = json.load(open(expanduser(join(data_dir, 'config.json'))))['rpc']
                    cfg_port = int(rpc['httpd_endpoint'].split(':')[1])
            except Exception as e:
                log.warning('Cannot read RPC config from %s' % data_dir)
                log.exception(e)
                rpc = {}
                cfg_port = None
        else:
            rpc = {}
            cfg_port = None

        self.witness_host     = client.get('witness_host')
        self.witness_port     = client.get('witness_port')
        self.witness_user     = client.get('witness_user')
        self.witness_password = client.get('witness_password')
        self.wallet_host      = client.get('wallet_host')
        self.wallet_port      = client.get('wallet_port') or client.get('rpc_port') or cfg_port or 0
        self.wallet_user      = client.get('wallet_user')
        self.wallet_password  = client.get('wallet_password')
        self.proxy_host       = client.get('proxy_host')
        self.proxy_port       = client.get('proxy_port')
        self.proxy_user       = client.get('proxy_user')
        self.proxy_password   = client.get('proxy_password')

        self.rpc_port = self.proxy_port or self.wallet_port
        self.rpc_user = self.wallet_user or client.get('rpc_user') or rpc.get('rpc_user') or ''
        self.rpc_password = self.wallet_password or client.get('rpc_password') or rpc.get('rpc_password') or ''
        self.rpc_host = self.wallet_host or client.get('rpc_host') or self.proxy_host or 'localhost'
        self.rpc_id = (self.rpc_host, self.wallet_port)
        self.ws_rpc_id = (self.witness_host, self.witness_port)
        self.venv_path = venv_path
        self.witness_id = witness_id
        self.witness_signing_key = signing_key or self.witness_signing_key
        self.bin_name = get_bin_name(client_name or 'bts')

        if self.is_graphene_based():
            # direct json-rpc call
            def direct_call(funcname, *args):
                # we want to avoid connecting to the client and block because
                # it is in a stopped state (eg: in gdb after having crashed)
                if self.is_localhost() and not bts_binary_running(self):
                    raise RPCError('Connection aborted: {} binary does not seem to be running'.format(self.type()))

                if self.proxy_host is not None and self.proxy_port is not None:
                    return rpc_call(self.proxy_host, self.proxy_port,
                                    None, None,
                                    funcname, *args, __graphene=True,
                                    rpc_args=dict(proxy_user=self.proxy_user,
                                                  proxy_password=self.proxy_password,
                                                  wallet_port=self.wallet_port))

                return rpc_call(self.wallet_host, self.wallet_port,
                                self.wallet_user, self.wallet_password,
                                funcname, *args, __graphene=True)
            self._rpc_call = direct_call

        elif self.rpc_host == 'localhost':
            # direct json-rpc call
            def local_call(funcname, *args):
                # we want to avoid connecting to the client and block because
                # it is in a stopped state (eg: in gdb after having crashed)
                if not bts_binary_running(self):
                    raise RPCError('Connection aborted: {} binary does not seem to be running'.format(self.type()))

                result = rpc_call('localhost', self.rpc_port,
                                  self.rpc_user, self.rpc_password,
                                  funcname, *args)
                return result
            self._rpc_call = local_call

        else:
            raise RuntimeError('Cannot connect to remote host for non-graphene nodes')

        if core.config.get('profile', False):
            self._rpc_call = core.profile(self._rpc_call)

        self.opts = kwargs
        if self.opts:
            log.debug('Additional opts for node {} on {}:{} - {}'.format(self.name, self.rpc_host, self.rpc_port, self.opts))

        # get a special "smart" cache for slots as it is a very expensive call
        self._slot_cache = make_region().configure('dogpile.cache.memory')

        # caches for committee member and witness names
        self._witness_names = {}
        self._committee_member_names = {}
Пример #3
0
    def __init__(self,
                 type,
                 name,
                 client=None,
                 monitoring=None,
                 rpc_port=None,
                 rpc_user=None,
                 rpc_password=None,
                 rpc_host=None,
                 venv_path=None,
                 desired_number_of_connections=None,
                 maximum_number_of_connections=None):
        self.type = type
        self.name = name
        self.monitoring = ([] if monitoring is None else [monitoring]
                           if not isinstance(monitoring, list) else monitoring)
        if client:
            data_dir = get_data_dir(client)

            try:
                log.info('Loading RPC config for %s from %s' %
                         (self.name, data_dir))
                rpc = json.load(open(expanduser(join(data_dir,
                                                     'config.json'))))['rpc']
                cfg_port = int(rpc['httpd_endpoint'].split(':')[1])
            except Exception:
                log.warning('Cannot read RPC config from %s' % data_dir)
                rpc = {}
                cfg_port = None
        else:
            rpc = {}
            cfg_port = None
        self.rpc_port = rpc_port or cfg_port or 0
        self.rpc_user = rpc_user or rpc.get('rpc_user') or ''
        self.rpc_password = rpc_password or rpc.get('rpc_password') or ''
        self.rpc_host = rpc_host or 'localhost'
        self.rpc_cache_key = (self.rpc_host, self.rpc_port)
        self.venv_path = venv_path
        self.bin_name = get_bin_name(client or 'bts')
        self.desired_number_of_connections = desired_number_of_connections
        self.maximum_number_of_connections = maximum_number_of_connections

        if self.rpc_host == 'localhost':
            # direct json-rpc call
            def local_call(funcname, *args):
                # we want to avoid connecting to the client and block because
                # it is in a stopped state (eg: in gdb after having crashed)
                if not bts_binary_running(self):
                    raise RPCError(
                        'Connection aborted: BTS binary does not seem to be running'
                    )

                result = rpc_call('localhost', self.rpc_port, self.rpc_user,
                                  self.rpc_password, funcname, *args)
                return result

            self._rpc_call = local_call

        else:
            # do it over ssh using bts-rpc
            # FIXME: make sure the password doesn't come out in an ssh log or bash history
            def remote_call(funcname, *args):
                cmd = 'ssh %s "' % self.rpc_host
                if self.venv_path:
                    cmd += 'source %s/bin/activate; ' % self.venv_path
                #cmd += 'bts-rpc %s %s"' % (funcname, '"%s"' % '" "'.join(str(arg) for arg in args))
                cmd += 'bts-rpc %d %s %s %s %s 2>/dev/null"' % (
                    self.rpc_port, self.rpc_user, self.rpc_password, funcname,
                    ' '.join(str(arg) for arg in args))

                result = run(cmd, io=True).stdout
                try:
                    result = json.loads(result)
                except:
                    log.error('Error while parsing JSON:')
                    log.error(result)
                    raise

                if 'error' in result:
                    # re-raise original exception
                    log.debug('Received error in RPC result: %s(%s)' %
                              (result['type'], result['error']))
                    try:
                        exc_module, exc_class = result['type'].rsplit('.', 1)
                    except ValueError:
                        exc_module, exc_class = 'builtins', result['type']

                    exc_class = getattr(importlib.import_module(exc_module),
                                        exc_class)
                    raise exc_class(result['error'])

                return result

            self._rpc_call = remote_call

        if core.config.get('profile', False):
            self._rpc_call = core.profile(self._rpc_call)

        # get a special "smart" cache for slots as it is a very expensive call
        self._slot_cache = make_region().configure('dogpile.cache.memory')