Example #1
0
    def test_path_config_defaults_for_linux(self):
        """Tests the default path configuration settings on Linux and other
        POSIX environments.

        Sets os.name to 'posix' (so the test works on all platforms), then
        compares all path settings to their expected default value.

            - config_dir = /etc/sawtooth
            - key_dir    = /etc/sawtooth/keys
            - data_dir   = /var/lib/sawtooth
            - log_dir    = /var/log/sawtooth

        Also specifies a configuration directory which does not exist (as we
        want to avoid loading any files for this test).

        The test also attempts to avoid environment variables from interfering
        with the test by clearing os.environ and restoring it after the test.
        """
        orig_os_name = os.name
        orig_environ = dict(os.environ)
        try:
            os.name = 'posix'
            os.environ.clear()

            config = load_path_config()
            self.assertEqual(config.config_dir, "/etc/sawtooth")
            self.assertEqual(config.key_dir, "/etc/sawtooth/keys")
            self.assertEqual(config.data_dir, "/var/lib/sawtooth")
            self.assertEqual(config.log_dir, "/var/log/sawtooth")
        finally:
            os.name = orig_os_name
            os.environ.update(orig_environ)
Example #2
0
def parse_permissions(permissions):
    roles = {}
    path_config = load_path_config()
    policy_dir = path_config.policy_dir
    if permissions is not None:
        for role_name in permissions:
            policy_name = permissions[role_name]
            policy_path = os.path.join(policy_dir, policy_name)
            rules = []
            if os.path.exists(policy_path):
                with open(policy_path) as policy_file:
                    rules = policy_file.read().splitlines()
                entries = []
                for rule in rules:
                    rule = rule.split(" ")
                    if rule[0] == "PERMIT_KEY":
                        entry = Policy.Entry(type=Policy.PERMIT_KEY,
                                             key=rule[1])
                        entries.append(entry)
                    elif rule[0] == "DENY_KEY":
                        entry = Policy.Entry(type=Policy.DENY_KEY, key=rule[1])
                        entries.append(entry)

                policy = Policy(name=policy_name, entries=entries)
                roles[role_name] = policy

            else:
                LOGGER.warning("%s does not exist. %s will not be set.",
                               policy_path, role_name)
    if not roles:
        return None
    return roles
Example #3
0
def parse_permissions(permissions):
    roles = {}
    path_config = load_path_config()
    policy_dir = path_config.policy_dir
    if permissions is not None:
        for role_name in permissions:
            policy_name = permissions[role_name]
            policy_path = os.path.join(policy_dir,
                                       policy_name)
            rules = []
            if os.path.exists(policy_path):
                with open(policy_path) as policy_file:
                    rules = policy_file.read().splitlines()
                entries = []
                for rule in rules:
                    rule = rule.split(" ")
                    if rule[0] == "PERMIT_KEY":
                        entry = Policy.Entry(type=Policy.PERMIT_KEY,
                                             key=rule[1])
                        entries.append(entry)
                    elif rule[0] == "DENY_KEY":
                        entry = Policy.Entry(type=Policy.DENY_KEY,
                                             key=rule[1])
                        entries.append(entry)

                policy = Policy(name=policy_name, entries=entries)
                roles[role_name] = policy

            else:
                LOGGER.warning("%s does not exist. %s will not be set.",
                               policy_path, role_name)
    if not roles:
        return None
    return roles
Example #4
0
def main(args=sys.argv[1:]):
    opts = parse_args(args)
    verbose_level = opts.verbose

    init_console_logging(verbose_level=verbose_level)

    try:
        path_config = load_path_config(config_dir=opts.config_dir)
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    for line in path_config.to_toml_string():
        LOGGER.info("config [path]: %s", line)

    # Process initial initialization errors, delaying the sys.exit(1) until
    # all errors have been reported to the user (via LOGGER.error()).  This
    # is intended to provide enough information to the user so they can correct
    # multiple errors before restarting the validator.
    init_errors = False

    if not check_directory(path=path_config.data_dir,
                           human_readable_name='Data'):
        init_errors = True
    if not check_directory(path=path_config.log_dir,
                           human_readable_name='Log'):
        init_errors = True

    try:
        identity_signing_key = load_identity_signing_key(
            key_dir=path_config.key_dir, key_name='validator')
    except LocalConfigurationError as e:
        LOGGER.error(str(e))
        init_errors = True

    if init_errors:
        LOGGER.error("Initialization errors occurred (see previous log "
                     "ERROR messages), shutting down.")
        sys.exit(1)

    validator = Validator(opts.network_endpoint, opts.component_endpoint,
                          opts.peers, path_config.data_dir,
                          identity_signing_key)

    # pylint: disable=broad-except
    try:
        validator.start()
    except KeyboardInterrupt:
        print("Interrupted!", file=sys.stderr)
        sys.exit(1)
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)
    except GenesisError as genesis_err:
        LOGGER.error(str(genesis_err))
        sys.exit(1)
    except Exception as e:
        LOGGER.exception(e)
        sys.exit(1)
Example #5
0
    def test_path_config_load_from_file(self):
        """Tests loading config settings from a TOML configuration file.

        Sets the SAWTOOTH_HOME environment variable to a temporary directory,
        writes a path.toml config file, then loads that config and verifies
        all the path settings are their expected values.

        The test also attempts to avoid environment variables from interfering
        with the test by clearing os.environ and restoring it after the test.
        """
        orig_environ = dict(os.environ)
        os.environ.clear()
        directory = tempfile.mkdtemp(prefix="test-path-config-")
        try:
            os.environ['SAWTOOTH_HOME'] = directory

            config_dir = os.path.join(directory, 'etc')
            os.mkdir(config_dir)

            with open(os.path.join(config_dir, 'path.toml'), 'w') as fd:
                fd.write('key_dir = "/tmp/no-such-dir-from-config/keys"')
                fd.write(os.linesep)
                fd.write('data_dir = "/tmp/no-such-dir-from-config/data"')
                fd.write(os.linesep)
                fd.write('log_dir = "/tmp/no-such-dir-from-config/logs"')
                fd.write(os.linesep)
                fd.write('policy_dir = "/tmp/no-such-dir-from-config/policy"')
                fd.write(os.linesep)

            config = load_path_config()
            self.assertEqual(config.config_dir, config_dir)
            self.assertEqual(config.key_dir,
                             "/tmp/no-such-dir-from-config/keys")
            self.assertEqual(config.data_dir,
                             "/tmp/no-such-dir-from-config/data")
            self.assertEqual(config.log_dir,
                             "/tmp/no-such-dir-from-config/logs")
            self.assertEqual(config.policy_dir,
                             "/tmp/no-such-dir-from-config/policy")
        finally:
            os.environ.clear()
            os.environ.update(orig_environ)
            shutil.rmtree(directory)
Example #6
0
    def test_path_config_load_from_file(self):
        """Tests loading config settings from a TOML configuration file.

        Sets the SAWTOOTH_HOME environment variable to a temporary directory,
        writes a path.toml config file, then loads that config and verifies
        all the path settings are their expected values.

        The test also attempts to avoid environment variables from interfering
        with the test by clearing os.environ and restoring it after the test.
        """
        orig_environ = dict(os.environ)
        os.environ.clear()
        directory = tempfile.mkdtemp(prefix="test-path-config-")
        try:
            os.environ['SAWTOOTH_HOME'] = directory

            config_dir = os.path.join(directory, 'etc')
            os.mkdir(config_dir)

            with open(os.path.join(config_dir, 'path.toml'), 'w') as fd:
                fd.write('key_dir = "/tmp/no-such-dir-from-config/keys"')
                fd.write(os.linesep)
                fd.write('data_dir = "/tmp/no-such-dir-from-config/data"')
                fd.write(os.linesep)
                fd.write('log_dir = "/tmp/no-such-dir-from-config/logs"')
                fd.write(os.linesep)
                fd.write('policy_dir = "/tmp/no-such-dir-from-config/policy"')
                fd.write(os.linesep)

            config = load_path_config()
            self.assertEqual(config.config_dir, config_dir)
            self.assertEqual(config.key_dir,
                             "/tmp/no-such-dir-from-config/keys")
            self.assertEqual(config.data_dir,
                             "/tmp/no-such-dir-from-config/data")
            self.assertEqual(config.log_dir,
                             "/tmp/no-such-dir-from-config/logs")
            self.assertEqual(config.policy_dir,
                             "/tmp/no-such-dir-from-config/policy")
        finally:
            os.environ.clear()
            os.environ.update(orig_environ)
            shutil.rmtree(directory)
Example #7
0
    def test_path_config_defaults_sawtooth_home(self):
        """Tests the default path configuration settings when SAWTOOTH_HOME
        is set.

        Sets the SAWTOOTH_HOME environment variable to
        /tmp/no-such-sawtooth-home, then compares all path settings for their
        expected values.

            - config_dir = /tmp/no-such-sawtooth-home/etc
            - key_dir    = /tmp/no-such-sawtooth-home/keys
            - data_dir   = /tmp/no-such-sawtooth-home/data
            - log_dir    = /tmp/no-such-sawtooth-home/logs

        Also specifies a configuration directory which does not exist (as we
        want to avoid loading any files for this test).  We use a different
        directory than SAWTOOTH_HOME as the config directory specified for
        config files should not impact the settings.

        The test also attempts to avoid environment variables from interfering
        with the test by clearing os.environ and restoring it after the test.
        """
        orig_environ = dict(os.environ)
        os.environ.clear()
        try:
            os.environ['SAWTOOTH_HOME'] = '/tmp/no-such-sawtooth-home'

            config = load_path_config()
            self.assertEqual(config.config_dir,
                             "/tmp/no-such-sawtooth-home/etc")
            self.assertEqual(config.key_dir,
                             "/tmp/no-such-sawtooth-home/keys")
            self.assertEqual(config.data_dir,
                             "/tmp/no-such-sawtooth-home/data")
            self.assertEqual(config.log_dir,
                             "/tmp/no-such-sawtooth-home/logs")
            self.assertEqual(config.policy_dir,
                             "/tmp/no-such-sawtooth-home/policy")
        finally:
            os.environ.clear()
            os.environ.update(orig_environ)
Example #8
0
    def test_path_config_defaults_sawtooth_home(self):
        """Tests the default path configuration settings when SAWTOOTH_HOME
        is set.

        Sets the SAWTOOTH_HOME environment variable to
        /tmp/no-such-sawtooth-home, then compares all path settings for their
        expected values.

            - config_dir = /tmp/no-such-sawtooth-home/etc
            - key_dir    = /tmp/no-such-sawtooth-home/keys
            - data_dir   = /tmp/no-such-sawtooth-home/data
            - log_dir    = /tmp/no-such-sawtooth-home/logs

        Also specifies a configuration directory which does not exist (as we
        want to avoid loading any files for this test).  We use a different
        directory than SAWTOOTH_HOME as the config directory specified for
        config files should not impact the settings.

        The test also attempts to avoid environment variables from interfering
        with the test by clearing os.environ and restoring it after the test.
        """
        orig_environ = dict(os.environ)
        os.environ.clear()
        try:
            os.environ['SAWTOOTH_HOME'] = '/tmp/no-such-sawtooth-home'

            config = load_path_config()
            self.assertEqual(config.config_dir,
                             "/tmp/no-such-sawtooth-home/etc")
            self.assertEqual(config.key_dir,
                             "/tmp/no-such-sawtooth-home/keys")
            self.assertEqual(config.data_dir,
                             "/tmp/no-such-sawtooth-home/data")
            self.assertEqual(config.log_dir,
                             "/tmp/no-such-sawtooth-home/logs")
            self.assertEqual(config.policy_dir,
                             "/tmp/no-such-sawtooth-home/policy")
        finally:
            os.environ.clear()
            os.environ.update(orig_environ)
Example #9
0
    def test_path_config_defaults_for_windows(self):
        """Tests the default path configuration settings on Windows operating
        systems.

        Sets os.name to 'nt' (so the test works on all platforms), then
        compares all path settings to their expected default value.

            - config_dir = /etc/sawtooth
            - key_dir    = /etc/sawtooth/keys
            - data_dir   = /var/lib/sawtooth
            - log_dir    = /var/log/sawtooth

        Also specifies a configuration directory which does not exist (as we
        want to avoid loading any files for this test).

        The test also attempts to avoid environment variables from interfering
        with the test by clearing os.environ and restoring it after the test.
        """
        orig_os_name = os.name
        orig_argv0 = sys.argv[0]
        try:
            os.name = 'nt'
            sys.argv[0] = "/tmp/no-such-directory/bin/validator"

            config = load_path_config()
            self.assertEqual(config.config_dir,
                             "/tmp/no-such-directory/conf")
            self.assertEqual(config.key_dir,
                             "/tmp/no-such-directory/conf/keys")
            self.assertEqual(config.data_dir,
                             "/tmp/no-such-directory/data")
            self.assertEqual(config.log_dir,
                             "/tmp/no-such-directory/logs")
        finally:
            os.name = orig_os_name
            sys.argv[0] = orig_argv0
Example #10
0
def main(args=None):
    if args is None:
        args = sys.argv[1:]
    opts = parse_args(args)
    verbose_level = opts.verbose

    # Determine if any args which support delimited lists should be
    # modified
    if opts.peers:
        opts.peers = _split_comma_append_args(opts.peers)

    if opts.seeds:
        opts.seeds = _split_comma_append_args(opts.seeds)

    init_console_logging(verbose_level=verbose_level)

    if opts.network_auth:
        opts.network_auth = {"network": opts.network_auth}

    try:
        path_config = load_path_config(config_dir=opts.config_dir)
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    try:
        opts_config = create_validator_config(opts)
        validator_config = \
            load_validator_config(opts_config, path_config.config_dir)
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    # Process initial initialization errors, delaying the sys.exit(1) until
    # all errors have been reported to the user (via LOGGER.error()).  This
    # is intended to provide enough information to the user so they can correct
    # multiple errors before restarting the validator.
    init_errors = False
    try:
        identity_signer = load_identity_signer(key_dir=path_config.key_dir,
                                               key_name='validator')
    except LocalConfigurationError as e:
        log_configuration(log_dir=path_config.log_dir, name="validator")
        LOGGER.error(str(e))
        init_errors = True

    log_config = get_log_config()
    if not init_errors:
        if log_config is not None:
            log_configuration(log_config=log_config)
            if log_config.get('root') is not None:
                init_console_logging(verbose_level=verbose_level)
        else:
            log_configuration(log_dir=path_config.log_dir, name="validator")

    try:
        version = pkg_resources.get_distribution(DISTRIBUTION_NAME).version
    except pkg_resources.DistributionNotFound:
        version = 'UNKNOWN'
    LOGGER.info('%s (Hyperledger Sawtooth) version %s', DISTRIBUTION_NAME,
                version)

    if LOGGER.isEnabledFor(logging.INFO):
        LOGGER.info('; '.join([
            'config [path]: {}'.format(line)
            for line in path_config.to_toml_string()
        ]))

    if not check_directory(path=path_config.data_dir,
                           human_readable_name='Data'):
        init_errors = True
    if not check_directory(path=path_config.log_dir,
                           human_readable_name='Log'):
        init_errors = True

    endpoint = validator_config.endpoint
    if endpoint is None:
        # Need to use join here to get the string "0.0.0.0". Otherwise,
        # bandit thinks we are binding to all interfaces and returns a
        # Medium security risk.
        interfaces = ["*", ".".join(["0", "0", "0", "0"])]
        interfaces += netifaces.interfaces()
        endpoint = validator_config.bind_network
        for interface in interfaces:
            if interface in validator_config.bind_network:
                LOGGER.error("Endpoint must be set when using %s", interface)
                init_errors = True
                break

    if init_errors:
        LOGGER.error("Initialization errors occurred (see previous log "
                     "ERROR messages), shutting down.")
        sys.exit(1)
    bind_network = validator_config.bind_network
    bind_component = validator_config.bind_component

    if "tcp://" not in bind_network:
        bind_network = "tcp://" + bind_network

    if "tcp://" not in bind_component:
        bind_component = "tcp://" + bind_component

    if validator_config.network_public_key is None or \
            validator_config.network_private_key is None:
        LOGGER.warning("Network key pair is not configured, Network "
                       "communications between validators will not be "
                       "authenticated or encrypted.")

    wrapped_registry = None
    metrics_reporter = None
    if validator_config.opentsdb_url:
        LOGGER.info("Adding metrics reporter: url=%s, db=%s",
                    validator_config.opentsdb_url,
                    validator_config.opentsdb_db)

        url = urlparse(validator_config.opentsdb_url)
        proto, db_server, db_port, = url.scheme, url.hostname, url.port

        registry = MetricsRegistry()
        wrapped_registry = MetricsRegistryWrapper(registry)

        metrics_reporter = InfluxReporter(
            registry=registry,
            reporting_interval=10,
            database=validator_config.opentsdb_db,
            prefix="sawtooth_validator",
            port=db_port,
            protocol=proto,
            server=db_server,
            username=validator_config.opentsdb_username,
            password=validator_config.opentsdb_password)
        metrics_reporter.start()

    # Verify state integrity before startup
    verify_state(bind_network, bind_component, validator_config.scheduler,
                 path_config.data_dir)

    LOGGER.info('Starting validator with %s scheduler',
                validator_config.scheduler)

    validator = Validator(bind_network,
                          bind_component,
                          endpoint,
                          validator_config.peering,
                          validator_config.seeds,
                          validator_config.peers,
                          path_config.data_dir,
                          path_config.config_dir,
                          identity_signer,
                          validator_config.scheduler,
                          validator_config.permissions,
                          validator_config.minimum_peer_connectivity,
                          validator_config.maximum_peer_connectivity,
                          validator_config.network_public_key,
                          validator_config.network_private_key,
                          roles=validator_config.roles,
                          metrics_registry=wrapped_registry)

    # pylint: disable=broad-except
    try:
        validator.start()
    except KeyboardInterrupt:
        LOGGER.info("Initiating graceful "
                    "shutdown (press Ctrl+C again to force)")
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)
    except GenesisError as genesis_err:
        LOGGER.error(str(genesis_err))
        sys.exit(1)
    except Exception as e:
        LOGGER.exception(e)
        sys.exit(1)
    finally:
        if metrics_reporter:
            metrics_reporter.stop()
        validator.stop()
Example #11
0
def main(args=None):
    if args is None:
        args = sys.argv[1:]
    opts = parse_args(args)
    verbose_level = opts.verbose

    # Determine if any args which support delimited lists should be
    # modified
    if opts.peers:
        opts.peers = _split_comma_append_args(opts.peers)

    if opts.seeds:
        opts.seeds = _split_comma_append_args(opts.seeds)

    init_console_logging(verbose_level=verbose_level)

    if opts.network_auth:
        opts.network_auth = {"network": opts.network_auth}

    try:
        path_config = load_path_config(config_dir=opts.config_dir)
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    try:
        opts_config = create_validator_config(opts)
        validator_config = \
            load_validator_config(opts_config, path_config.config_dir)
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    # Process initial initialization errors, delaying the sys.exit(1) until
    # all errors have been reported to the user (via LOGGER.error()).  This
    # is intended to provide enough information to the user so they can correct
    # multiple errors before restarting the validator.
    init_errors = False
    try:
        identity_signer = load_identity_signer(
            key_dir=path_config.key_dir,
            key_name='validator')
    except LocalConfigurationError as e:
        log_configuration(log_dir=path_config.log_dir,
                          name="validator")
        LOGGER.error(str(e))
        init_errors = True

    log_config = get_log_config()
    if not init_errors:
        if log_config is not None:
            log_configuration(log_config=log_config)
            if log_config.get('root') is not None:
                init_console_logging(verbose_level=verbose_level)
        else:
            log_configuration(log_dir=path_config.log_dir,
                              name="validator")

    try:
        version = pkg_resources.get_distribution(DISTRIBUTION_NAME).version
    except pkg_resources.DistributionNotFound:
        version = 'UNKNOWN'
    LOGGER.info(
        '%s (Hyperledger Sawtooth) version %s', DISTRIBUTION_NAME, version)

    if LOGGER.isEnabledFor(logging.INFO):
        LOGGER.info(
            '; '.join([
                'config [path]: {}'.format(line)
                for line in path_config.to_toml_string()
            ])
        )

    if not check_directory(path=path_config.data_dir,
                           human_readable_name='Data'):
        init_errors = True
    if not check_directory(path=path_config.log_dir,
                           human_readable_name='Log'):
        init_errors = True

    endpoint = validator_config.endpoint
    if endpoint is None:
        # Need to use join here to get the string "0.0.0.0". Otherwise,
        # bandit thinks we are binding to all interfaces and returns a
        # Medium security risk.
        interfaces = ["*", ".".join(["0", "0", "0", "0"])]
        interfaces += netifaces.interfaces()
        endpoint = validator_config.bind_network
        for interface in interfaces:
            if interface in validator_config.bind_network:
                LOGGER.error("Endpoint must be set when using %s", interface)
                init_errors = True
                break

    if init_errors:
        LOGGER.error("Initialization errors occurred (see previous log "
                     "ERROR messages), shutting down.")
        sys.exit(1)
    bind_network = validator_config.bind_network
    bind_component = validator_config.bind_component

    if "tcp://" not in bind_network:
        bind_network = "tcp://" + bind_network

    if "tcp://" not in bind_component:
        bind_component = "tcp://" + bind_component

    if validator_config.network_public_key is None or \
            validator_config.network_private_key is None:
        LOGGER.warning("Network key pair is not configured, Network "
                       "communications between validators will not be "
                       "authenticated or encrypted.")

    wrapped_registry = None
    metrics_reporter = None
    if validator_config.opentsdb_url:
        LOGGER.info("Adding metrics reporter: url=%s, db=%s",
                    validator_config.opentsdb_url,
                    validator_config.opentsdb_db)

        url = urlparse(validator_config.opentsdb_url)
        proto, db_server, db_port, = url.scheme, url.hostname, url.port

        registry = MetricsRegistry()
        wrapped_registry = MetricsRegistryWrapper(registry)

        metrics_reporter = InfluxReporter(
            registry=registry,
            reporting_interval=10,
            database=validator_config.opentsdb_db,
            prefix="sawtooth_validator",
            port=db_port,
            protocol=proto,
            server=db_server,
            username=validator_config.opentsdb_username,
            password=validator_config.opentsdb_password)
        metrics_reporter.start()

    LOGGER.info(
        'Starting validator with %s scheduler',
        validator_config.scheduler)

    validator = Validator(
        bind_network,
        bind_component,
        endpoint,
        validator_config.peering,
        validator_config.seeds,
        validator_config.peers,
        path_config.data_dir,
        path_config.config_dir,
        identity_signer,
        validator_config.scheduler,
        validator_config.permissions,
        validator_config.minimum_peer_connectivity,
        validator_config.maximum_peer_connectivity,
        validator_config.network_public_key,
        validator_config.network_private_key,
        roles=validator_config.roles,
        metrics_registry=wrapped_registry)

    # pylint: disable=broad-except
    try:
        validator.start()
    except KeyboardInterrupt:
        LOGGER.info("Initiating graceful "
                    "shutdown (press Ctrl+C again to force)")
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)
    except GenesisError as genesis_err:
        LOGGER.error(str(genesis_err))
        sys.exit(1)
    except Exception as e:
        LOGGER.exception(e)
        sys.exit(1)
    finally:
        if metrics_reporter:
            metrics_reporter.stop()
        validator.stop()
Example #12
0
def main(args=sys.argv[1:]):
    opts = parse_args(args)
    verbose_level = opts.verbose

    # Determine if any args which support delimited lists should be
    # modified
    if opts.peers:
        opts.peers = _split_comma_append_args(opts.peers)

    if opts.join:
        opts.join = _split_comma_append_args(opts.join)

    init_console_logging(verbose_level=verbose_level)

    try:
        path_config = load_path_config(config_dir=opts.config_dir)
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    # Process initial initialization errors, delaying the sys.exit(1) until
    # all errors have been reported to the user (via LOGGER.error()).  This
    # is intended to provide enough information to the user so they can correct
    # multiple errors before restarting the validator.
    init_errors = False

    try:
        identity_signing_key = load_identity_signing_key(
            key_dir=path_config.key_dir, key_name='validator')
        pubkey = signing.generate_pubkey(identity_signing_key)
    except LocalConfigurationError as e:
        log_configuration(log_dir=path_config.log_dir, name="validator")
        LOGGER.error(str(e))
        init_errors = True

    log_config = get_log_config()
    if not init_errors:
        if log_config is not None:
            log_configuration(log_config=log_config)
            if log_config.get('root') is not None:
                init_console_logging(verbose_level=verbose_level)
        else:
            log_configuration(log_dir=path_config.log_dir,
                              name="validator-" + pubkey[:8])

    for line in path_config.to_toml_string():
        LOGGER.info("config [path]: %s", line)

    if not check_directory(path=path_config.data_dir,
                           human_readable_name='Data'):
        init_errors = True
    if not check_directory(path=path_config.log_dir,
                           human_readable_name='Log'):
        init_errors = True

    if init_errors:
        LOGGER.error("Initialization errors occurred (see previous log "
                     "ERROR messages), shutting down.")
        sys.exit(1)

    validator = Validator(opts.network_endpoint, opts.component_endpoint,
                          opts.public_uri, opts.peering, opts.join, opts.peers,
                          path_config.data_dir, identity_signing_key)

    # pylint: disable=broad-except
    try:
        validator.start()
    except KeyboardInterrupt:
        LOGGER.info("Initiating graceful "
                    "shutdown (press Ctrl+C again to force)")
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)
    except GenesisError as genesis_err:
        LOGGER.error(str(genesis_err))
        sys.exit(1)
    except Exception as e:
        LOGGER.exception(e)
        sys.exit(1)
    finally:
        validator.stop()
Example #13
0
def main(args):
    try:
        path_config = load_path_config(config_dir=args['config_dir'])
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    try:
        opts_config = ValidatorConfig(
            bind_component=args['bind_component'],
            bind_network=args['bind_network'],
            bind_consensus=args['bind_consensus'],
            endpoint=args['endpoint'],
            maximum_peer_connectivity=args['maximum_peer_connectivity'],
            minimum_peer_connectivity=args['minimum_peer_connectivity'],
            roles=args['roles'],
            opentsdb_db=args['opentsdb_db'],
            opentsdb_url=args['opentsdb_url'],
            peering=args['peering'],
            peers=args['peers'],
            scheduler=args['scheduler'],
            seeds=args['seeds'],
            state_pruning_block_depth=args['state_pruning_block_depth'],
            fork_cache_keep_time=args['fork_cache_keep_time'],
        )

        validator_config = \
            load_validator_config(opts_config, path_config.config_dir)
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    try:
        log_configuration(log_dir=path_config.log_dir, name="validator")
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    # Process initial initialization errors, delaying the sys.exit(1) until
    # all errors have been reported to the user (via LOGGER.error()).  This
    # is intended to provide enough information to the user so they can correct
    # multiple errors before restarting the validator.
    init_errors = False
    try:
        identity_signer = load_identity_signer(key_dir=path_config.key_dir,
                                               key_name='validator')
    except LocalConfigurationError as e:
        LOGGER.error(str(e))
        init_errors = True

    log_config = get_log_config()
    if not init_errors:
        if log_config is not None:
            log_configuration(log_config=log_config)
            if log_config.get('root') is not None:
                init_console_logging(verbose_level=args['verbose'])
        else:
            log_configuration(log_dir=path_config.log_dir, name="validator")

    try:
        version = pkg_resources.get_distribution(DISTRIBUTION_NAME).version
    except pkg_resources.DistributionNotFound:
        version = 'UNKNOWN'
    LOGGER.info('%s (Hyperledger Sawtooth) version %s', DISTRIBUTION_NAME,
                version)

    if LOGGER.isEnabledFor(logging.INFO):
        LOGGER.info('; '.join([
            'config [path]: {}'.format(line)
            for line in path_config.to_toml_string()
        ]))

    if not check_directory(path=path_config.data_dir,
                           human_readable_name='Data'):
        init_errors = True
    if not check_directory(path=path_config.log_dir,
                           human_readable_name='Log'):
        init_errors = True

    endpoint = validator_config.endpoint
    if endpoint is None:
        # Need to use join here to get the string "0.0.0.0". Otherwise,
        # bandit thinks we are binding to all interfaces and returns a
        # Medium security risk.
        interfaces = ["*", ".".join(["0", "0", "0", "0"])]
        interfaces += netifaces.interfaces()
        endpoint = validator_config.bind_network
        parsed_endpoint = urlparse(validator_config.bind_network)
        for interface in interfaces:
            if interface == parsed_endpoint.hostname:
                LOGGER.error("Endpoint must be set when using %s", interface)
                init_errors = True

    if init_errors:
        LOGGER.error("Initialization errors occurred (see previous log "
                     "ERROR messages), shutting down.")
        sys.exit(1)
    bind_network = validator_config.bind_network
    bind_component = validator_config.bind_component
    bind_consensus = validator_config.bind_consensus

    if "tcp://" not in bind_network:
        bind_network = "tcp://" + bind_network

    if "tcp://" not in bind_component:
        bind_component = "tcp://" + bind_component

    if bind_consensus and "tcp://" not in bind_consensus:
        bind_consensus = "tcp://" + bind_consensus

    if validator_config.network_public_key is None or \
            validator_config.network_private_key is None:
        LOGGER.warning("Network key pair is not configured, Network "
                       "communications between validators will not be "
                       "authenticated or encrypted.")

    metrics_reporter = None
    if validator_config.opentsdb_url:
        LOGGER.info("Adding metrics reporter: url=%s, db=%s",
                    validator_config.opentsdb_url,
                    validator_config.opentsdb_db)

        url = urlparse(validator_config.opentsdb_url)
        proto, db_server, db_port, = url.scheme, url.hostname, url.port

        registry = MetricsRegistry()
        metrics.init_metrics(registry=registry)

        metrics_reporter = InfluxReporter(
            registry=registry,
            reporting_interval=10,
            database=validator_config.opentsdb_db,
            prefix="sawtooth_validator",
            port=db_port,
            protocol=proto,
            server=db_server,
            username=validator_config.opentsdb_username,
            password=validator_config.opentsdb_password)
        metrics_reporter.start()
    else:
        metrics.init_metrics()

    # Verify state integrity before startup
    global_state_db, blockstore = state_verifier.get_databases(
        bind_network, path_config.data_dir)

    state_verifier.verify_state(global_state_db, blockstore, bind_component,
                                validator_config.scheduler)

    # Explicitly drop this, so there are not two db instances
    global_state_db.drop()
    global_state_db = None

    LOGGER.info('Starting validator with %s scheduler',
                validator_config.scheduler)

    component_workers = validator_config.component_thread_pool_workers
    network_workers = validator_config.network_thread_pool_workers
    sig_workers = validator_config.signature_thread_pool_workers
    validator = Validator(bind_network,
                          bind_component,
                          bind_consensus,
                          endpoint,
                          validator_config.peering,
                          validator_config.seeds,
                          validator_config.peers,
                          path_config.data_dir,
                          path_config.config_dir,
                          identity_signer,
                          path_config.key_dir,
                          validator_config.scheduler,
                          validator_config.permissions,
                          validator_config.minimum_peer_connectivity,
                          validator_config.maximum_peer_connectivity,
                          validator_config.state_pruning_block_depth,
                          validator_config.fork_cache_keep_time,
                          validator_config.network_public_key,
                          validator_config.network_private_key,
                          roles=validator_config.roles,
                          component_thread_pool_workers=component_workers,
                          network_thread_pool_workers=network_workers,
                          signature_thread_pool_workers=sig_workers)

    # pylint: disable=broad-except
    try:
        validator.start()
    except KeyboardInterrupt:
        LOGGER.info("Initiating graceful "
                    "shutdown (press Ctrl+C again to force)")
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)
    except GenesisError as genesis_err:
        LOGGER.error(str(genesis_err))
        sys.exit(1)
    except Exception as e:
        LOGGER.exception(e)
        sys.exit(1)
    finally:
        if metrics_reporter:
            metrics_reporter.stop()
        validator.stop()
Example #14
0
def main(args):
    try:
        path_config = load_path_config(config_dir=args['config_dir'])
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    try:
        opts_config = ValidatorConfig(
            bind_component=args['bind_component'],
            bind_network=args['bind_network'],
            bind_consensus=args['bind_consensus'],
            endpoint=args['endpoint'],
            maximum_peer_connectivity=args['maximum_peer_connectivity'],
            minimum_peer_connectivity=args['minimum_peer_connectivity'],
            roles=args['roles'],
            opentsdb_db=args['opentsdb_db'],
            opentsdb_url=args['opentsdb_url'],
            peering=args['peering'],
            peers=args['peers'],
            scheduler=args['scheduler'],
            seeds=args['seeds'],
            state_pruning_block_depth=args['state_pruning_block_depth'],
            fork_cache_keep_time=args['fork_cache_keep_time'],
        )

        validator_config = \
            load_validator_config(opts_config, path_config.config_dir)
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    try:
        log_configuration(log_dir=path_config.log_dir,
                          name="validator")
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    # Process initial initialization errors, delaying the sys.exit(1) until
    # all errors have been reported to the user (via LOGGER.error()).  This
    # is intended to provide enough information to the user so they can correct
    # multiple errors before restarting the validator.
    init_errors = False
    try:
        identity_signer = load_identity_signer(
            key_dir=path_config.key_dir,
            key_name='validator')
    except LocalConfigurationError as e:
        LOGGER.error(str(e))
        init_errors = True

    log_config = get_log_config()
    if not init_errors:
        if log_config is not None:
            log_configuration(log_config=log_config)
            if log_config.get('root') is not None:
                init_console_logging(verbose_level=args['verbose'])
        else:
            log_configuration(log_dir=path_config.log_dir,
                              name="validator")

    try:
        version = pkg_resources.get_distribution(DISTRIBUTION_NAME).version
    except pkg_resources.DistributionNotFound:
        version = 'UNKNOWN'
    LOGGER.info(
        '%s (Hyperledger Sawtooth) version %s', DISTRIBUTION_NAME, version)

    if LOGGER.isEnabledFor(logging.INFO):
        LOGGER.info(
            '; '.join([
                'config [path]: {}'.format(line)
                for line in path_config.to_toml_string()
            ])
        )

    if not check_directory(path=path_config.data_dir,
                           human_readable_name='Data'):
        init_errors = True
    if not check_directory(path=path_config.log_dir,
                           human_readable_name='Log'):
        init_errors = True

    endpoint = validator_config.endpoint
    if endpoint is None:
        # Need to use join here to get the string "0.0.0.0". Otherwise,
        # bandit thinks we are binding to all interfaces and returns a
        # Medium security risk.
        interfaces = ["*", ".".join(["0", "0", "0", "0"])]
        interfaces += netifaces.interfaces()
        endpoint = validator_config.bind_network
        parsed_endpoint = urlparse(validator_config.bind_network)
        for interface in interfaces:
            if interface == parsed_endpoint.hostname:
                LOGGER.error("Endpoint must be set when using %s", interface)
                init_errors = True

    if init_errors:
        LOGGER.error("Initialization errors occurred (see previous log "
                     "ERROR messages), shutting down.")
        sys.exit(1)
    bind_network = validator_config.bind_network
    bind_component = validator_config.bind_component
    bind_consensus = validator_config.bind_consensus

    if "tcp://" not in bind_network:
        bind_network = "tcp://" + bind_network

    if "tcp://" not in bind_component:
        bind_component = "tcp://" + bind_component

    if bind_consensus and "tcp://" not in bind_consensus:
        bind_consensus = "tcp://" + bind_consensus

    if validator_config.network_public_key is None or \
            validator_config.network_private_key is None:
        LOGGER.warning("Network key pair is not configured, Network "
                       "communications between validators will not be "
                       "authenticated or encrypted.")

    metrics_reporter = None
    if validator_config.opentsdb_url:
        LOGGER.info("Adding metrics reporter: url=%s, db=%s",
                    validator_config.opentsdb_url,
                    validator_config.opentsdb_db)

        url = urlparse(validator_config.opentsdb_url)
        proto, db_server, db_port, = url.scheme, url.hostname, url.port

        registry = MetricsRegistry()
        metrics.init_metrics(registry=registry)

        metrics_reporter = InfluxReporter(
            registry=registry,
            reporting_interval=10,
            database=validator_config.opentsdb_db,
            prefix="sawtooth_validator",
            port=db_port,
            protocol=proto,
            server=db_server,
            username=validator_config.opentsdb_username,
            password=validator_config.opentsdb_password)
        metrics_reporter.start()
    else:
        metrics.init_metrics()

    # Verify state integrity before startup
    global_state_db, blockstore = state_verifier.get_databases(
        bind_network,
        path_config.data_dir)

    state_verifier.verify_state(
        global_state_db,
        blockstore,
        bind_component,
        validator_config.scheduler)

    # Explicitly drop this, so there are not two db instances
    global_state_db.drop()
    global_state_db = None

    LOGGER.info(
        'Starting validator with %s scheduler',
        validator_config.scheduler)

    component_workers = validator_config.component_thread_pool_workers
    network_workers = validator_config.network_thread_pool_workers
    sig_workers = validator_config.signature_thread_pool_workers
    validator = Validator(
        bind_network,
        bind_component,
        bind_consensus,
        endpoint,
        validator_config.peering,
        validator_config.seeds,
        validator_config.peers,
        path_config.data_dir,
        path_config.config_dir,
        identity_signer,
        validator_config.scheduler,
        validator_config.permissions,
        validator_config.minimum_peer_connectivity,
        validator_config.maximum_peer_connectivity,
        validator_config.state_pruning_block_depth,
        validator_config.fork_cache_keep_time,
        validator_config.network_public_key,
        validator_config.network_private_key,
        roles=validator_config.roles,
        component_thread_pool_workers=component_workers,
        network_thread_pool_workers=network_workers,
        signature_thread_pool_workers=sig_workers)

    # pylint: disable=broad-except
    try:
        validator.start()
    except KeyboardInterrupt:
        LOGGER.info("Initiating graceful "
                    "shutdown (press Ctrl+C again to force)")
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)
    except GenesisError as genesis_err:
        LOGGER.error(str(genesis_err))
        sys.exit(1)
    except Exception as e:
        LOGGER.exception(e)
        sys.exit(1)
    finally:
        if metrics_reporter:
            metrics_reporter.stop()
        validator.stop()
Example #15
0
def main(args=None):
    if args is None:
        args = sys.argv[1:]
    opts = parse_args(args)
    verbose_level = opts.verbose

    # Determine if any args which support delimited lists should be
    # modified
    if opts.peers:
        opts.peers = _split_comma_append_args(opts.peers)

    if opts.seeds:
        opts.seeds = _split_comma_append_args(opts.seeds)

    init_console_logging(verbose_level=verbose_level)

    try:
        path_config = load_path_config(config_dir=opts.config_dir)
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    try:
        opts_config = create_validator_config(opts)
        validator_config = \
            load_validator_config(opts_config, path_config.config_dir)
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    # Process initial initialization errors, delaying the sys.exit(1) until
    # all errors have been reported to the user (via LOGGER.error()).  This
    # is intended to provide enough information to the user so they can correct
    # multiple errors before restarting the validator.
    init_errors = False
    try:
        identity_signing_key = load_identity_signing_key(
            key_dir=path_config.key_dir, key_name='validator')
        pubkey = signing.generate_pubkey(identity_signing_key)
    except LocalConfigurationError as e:
        log_configuration(log_dir=path_config.log_dir, name="validator")
        LOGGER.error(str(e))
        init_errors = True

    log_config = get_log_config()
    if not init_errors:
        if log_config is not None:
            log_configuration(log_config=log_config)
            if log_config.get('root') is not None:
                init_console_logging(verbose_level=verbose_level)
        else:
            log_configuration(log_dir=path_config.log_dir,
                              name="validator-" + pubkey[:8])

    for line in path_config.to_toml_string():
        LOGGER.info("config [path]: %s", line)

    if not check_directory(path=path_config.data_dir,
                           human_readable_name='Data'):
        init_errors = True
    if not check_directory(path=path_config.log_dir,
                           human_readable_name='Log'):
        init_errors = True

    endpoint = validator_config.endpoint
    if endpoint is None:
        # Need to use join here to get the string "0.0.0.0". Otherwise,
        # bandit thinks we are binding to all interfaces and returns a
        # Medium security risk.
        interfaces = ["*", ".".join(["0", "0", "0", "0"])]
        interfaces += netifaces.interfaces()
        endpoint = validator_config.bind_network
        for interface in interfaces:
            if interface in validator_config.bind_network:
                LOGGER.error("Endpoint must be set when using %s", interface)
                init_errors = True
                break

    if init_errors:
        LOGGER.error("Initialization errors occurred (see previous log "
                     "ERROR messages), shutting down.")
        sys.exit(1)

    bind_network = validator_config.bind_network
    bind_component = validator_config.bind_component

    if "tcp://" not in bind_network:
        bind_network = "tcp://" + bind_network

    if "tcp://" not in bind_component:
        bind_component = "tcp://" + bind_component

    if validator_config.network_public_key is None or \
            validator_config.network_private_key is None:
        LOGGER.warning("Network key pair is not configured, Network "
                       "communications between validators will not be "
                       "authenticated or encrypted.")

    validator = Validator(bind_network, bind_component, endpoint,
                          validator_config.peering, validator_config.seeds,
                          validator_config.peers, path_config.data_dir,
                          path_config.config_dir, identity_signing_key,
                          validator_config.scheduler,
                          validator_config.permissions,
                          validator_config.network_public_key,
                          validator_config.network_private_key)

    # pylint: disable=broad-except
    try:
        validator.start()
    except KeyboardInterrupt:
        LOGGER.info("Initiating graceful "
                    "shutdown (press Ctrl+C again to force)")
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)
    except GenesisError as genesis_err:
        LOGGER.error(str(genesis_err))
        sys.exit(1)
    except Exception as e:
        LOGGER.exception(e)
        sys.exit(1)
    finally:
        validator.stop()
Example #16
0
def main(args=None):
    if args is None:
        args = sys.argv[1:]
    opts = parse_args(args)
    verbose_level = opts.verbose

    # Determine if any args which support delimited lists should be
    # modified
    if opts.peers:
        opts.peers = _split_comma_append_args(opts.peers)

    if opts.seeds:
        opts.seeds = _split_comma_append_args(opts.seeds)

    init_console_logging(verbose_level=verbose_level)

    try:
        path_config = load_path_config(config_dir=opts.config_dir)
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    try:
        opts_config = create_validator_config(opts)
        validator_config = \
            load_validator_config(opts_config, path_config.config_dir)
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)

    # Process initial initialization errors, delaying the sys.exit(1) until
    # all errors have been reported to the user (via LOGGER.error()).  This
    # is intended to provide enough information to the user so they can correct
    # multiple errors before restarting the validator.
    init_errors = False

    try:
        identity_signing_key = load_identity_signing_key(
            key_dir=path_config.key_dir,
            key_name='validator')
        pubkey = signing.generate_pubkey(identity_signing_key)
    except LocalConfigurationError as e:
        log_configuration(log_dir=path_config.log_dir,
                          name="validator")
        LOGGER.error(str(e))
        init_errors = True

    log_config = get_log_config()
    if not init_errors:
        if log_config is not None:
            log_configuration(log_config=log_config)
            if log_config.get('root') is not None:
                init_console_logging(verbose_level=verbose_level)
        else:
            log_configuration(log_dir=path_config.log_dir,
                              name="validator-" + pubkey[:8])

    for line in path_config.to_toml_string():
        LOGGER.info("config [path]: %s", line)

    if not check_directory(path=path_config.data_dir,
                           human_readable_name='Data'):
        init_errors = True
    if not check_directory(path=path_config.log_dir,
                           human_readable_name='Log'):
        init_errors = True

    endpoint = validator_config.endpoint
    if endpoint is None:
        # Need to use join here to get the string "0.0.0.0". Otherwise,
        # bandit thinks we are binding to all interfaces and returns a
        # Medium security risk.
        interfaces = ["*", ".".join(["0", "0", "0", "0"])]
        interfaces += netifaces.interfaces()
        endpoint = validator_config.bind_network
        for interface in interfaces:
            if interface in validator_config.bind_network:
                LOGGER.error("Endpoint must be set when using %s", interface)
                init_errors = True
                break

    if init_errors:
        LOGGER.error("Initialization errors occurred (see previous log "
                     "ERROR messages), shutting down.")
        sys.exit(1)

    bind_network = validator_config.bind_network
    bind_component = validator_config.bind_component

    if "tcp://" not in bind_network:
        bind_network = "tcp://" + bind_network

    if "tcp://" not in bind_component:
        bind_component = "tcp://" + bind_component

    if validator_config.network_public_key is None or \
            validator_config.network_private_key is None:
        LOGGER.warning("Network key pair is not configured, Network "
                       "communications between validators will not be "
                       "authenticated or encrypted.")

    validator = Validator(bind_network,
                          bind_component,
                          endpoint,
                          validator_config.peering,
                          validator_config.seeds,
                          validator_config.peers,
                          path_config.data_dir,
                          path_config.config_dir,
                          identity_signing_key,
                          validator_config.network_public_key,
                          validator_config.network_private_key)

    # pylint: disable=broad-except
    try:
        validator.start()
    except KeyboardInterrupt:
        LOGGER.info("Initiating graceful "
                    "shutdown (press Ctrl+C again to force)")
    except LocalConfigurationError as local_config_err:
        LOGGER.error(str(local_config_err))
        sys.exit(1)
    except GenesisError as genesis_err:
        LOGGER.error(str(genesis_err))
        sys.exit(1)
    except Exception as e:
        LOGGER.exception(e)
        sys.exit(1)
    finally:
        validator.stop()