示例#1
0
def do_genesis(args, data_dir):
    """Given the command args, take an series of input files containing
    GenesisData, combine all the batches into one GenesisData, and output the
    result into a new file.
    """
    genesis_batches = []
    for input_file in args.input_file:
        print('Processing {}...'.format(input_file))
        input_data = BatchList()
        try:
            with open(input_file, 'rb') as in_file:
                input_data.ParseFromString(in_file.read())
        except:
            raise CliException('Unable to read {}'.format(input_file))

        genesis_batches += input_data.batches

    _validate_depedencies(genesis_batches)
    if args.output:
        genesis_file = args.output
    else:
        genesis_file = os.path.join(data_dir, 'genesis.batch')

    print('Generating {}'.format(genesis_file))
    output_data = GenesisData(batches=genesis_batches)
    with open(genesis_file, 'wb') as out_file:
        out_file.write(output_data.SerializeToString())
示例#2
0
def _do_config_set(args):
    """Executes the 'set' subcommand.  Given a key file, and a series of
    key/value pairs, it generates batches of sawtooth_config transactions in a
    BatchList instance, and stores it in a file.
    """
    settings = [s.split('=', 1) for s in args.setting]

    with open(args.key, 'r') as key_file:
        wif_key = key_file.read().strip()
        signing_key = bitcoin.encode_privkey(
            bitcoin.decode_privkey(wif_key, 'wif'), 'hex')
        pubkey = bitcoin.encode_pubkey(bitcoin.privkey_to_pubkey(signing_key),
                                       'hex')

    txns = [
        _create_config_txn(pubkey, signing_key, setting)
        for setting in settings
    ]
    txn_ids = [txn.header_signature for txn in txns]

    batch_header = BatchHeader(signer_pubkey=pubkey,
                               transaction_ids=txn_ids).SerializeToString()

    batch = Batch(header=batch_header,
                  header_signature=bitcoin.ecdsa_sign(batch_header,
                                                      signing_key),
                  transactions=txns)

    batch_list = BatchList(batches=[batch]).SerializeToString()

    try:
        with open(args.output, 'wb') as batch_file:
            batch_file.write(batch_list)
    except:
        raise CliException('Unable to write to {}'.format(args.output))
示例#3
0
def _do_identity_role_create(args):
    """Executes the 'role create' subcommand.  Given a key file, a role name,
    and a policy name it generates a batch of sawtooth_identity
    transactions in a BatchList instance. The BatchList is either stored to a
    file or submitted to a validator, depending on the supplied CLI arguments.
    """
    pubkey, signing_key = _read_signing_keys(args.key)
    txns = [_create_role_txn(pubkey, signing_key, args.name,
            args.policy)]

    batch = _create_batch(pubkey, signing_key, txns)

    batch_list = BatchList(batches=[batch])

    if args.output is not None:
        try:
            with open(args.output, 'wb') as batch_file:
                batch_file.write(batch_list.SerializeToString())
        except IOError as e:
            raise CliException(
                'Unable to write to batch file: {}'.format(str(e)))
    elif args.url is not None:
        rest_client = RestClient(args.url)
        rest_client.send_batches(batch_list)
    else:
        raise AssertionError('No target for create set.')
示例#4
0
def do_block(args):
    """Runs the block list or block show command, printing output to the console

        Args:
            args: The parsed arguments sent to the command at runtime
    """
    rest_client = RestClient(args.url, args.user)

    if args.subcommand == 'list':
        blocks = rest_client.list_blocks(limit=args.limit)
        keys = ('num', 'block_id', 'batches', 'txns', 'signer')
        headers = tuple(k.upper() if k != 'batches' else 'BATS' for k in keys)

        def parse_block_row(block):
            batches = block.get('batches', [])
            txns = [t for b in batches for t in b['transactions']]
            return (block['header'].get('block_num',
                                        0), block['header_signature'],
                    len(batches), len(txns),
                    block['header']['signer_public_key'])

        if args.format == 'default':
            fmt.print_terminal_table(headers, blocks, parse_block_row)

        elif args.format == 'csv':
            fmt.print_csv(headers, blocks, parse_block_row)

        elif args.format == 'json' or args.format == 'yaml':
            data = [{k: d
                     for k, d in zip(keys, parse_block_row(b))}
                    for b in blocks]

            if args.format == 'yaml':
                fmt.print_yaml(data)
            elif args.format == 'json':
                fmt.print_json(data)
            else:
                raise AssertionError('Missing handler: {}'.format(args.format))

        else:
            raise AssertionError('Missing handler: {}'.format(args.format))

    if args.subcommand == 'show':
        output = rest_client.get_block(args.block_id)

        if args.key:
            if args.key in output:
                output = output[args.key]
            elif args.key in output['header']:
                output = output['header'][args.key]
            else:
                raise CliException(
                    'key "{}" not found in block or header'.format(args.key))

        if args.format == 'yaml':
            fmt.print_yaml(output)
        elif args.format == 'json':
            fmt.print_json(output)
        else:
            raise AssertionError('Missing handler: {}'.format(args.format))
示例#5
0
def _do_config_proposal_create(args):
    """Executes the 'proposal create' subcommand.  Given a key file, and a
    series of key/value pairs, it generates batches of sawtooth_settings
    transactions in a BatchList instance.  The BatchList is either stored to a
    file or submitted to a validator, depending on the supplied CLI arguments.
    """
    settings = [s.split('=', 1) for s in args.setting]

    public_key, signing_key = _read_signing_keys(args.key)

    txns = [
        _create_propose_txn(public_key, signing_key, setting)
        for setting in settings
    ]

    batch = _create_batch(public_key, signing_key, txns)

    batch_list = BatchList(batches=[batch])

    if args.output is not None:
        try:
            with open(args.output, 'wb') as batch_file:
                batch_file.write(batch_list.SerializeToString())
        except IOError as e:
            raise CliException('Unable to write to batch file: {}'.format(
                str(e)))
    elif args.url is not None:
        rest_client = RestClient(args.url)
        rest_client.send_batches(batch_list)
    else:
        raise AssertionError('No target for create set.')
示例#6
0
def do_peers(args):
    if args.peers_command == 'list':
        _do_peers_list(args)
    elif args.peers_command == 'graph':
        _do_peers_graph(args)
    else:
        raise CliException('Invalid command: {}'.format(args.subcommand))
示例#7
0
def main(prog_name=os.path.basename(sys.argv[0]), args=None,
         with_loggers=True):
    parser = create_parser(prog_name)
    if args is None:
        args = sys.argv[1:]
    args = parser.parse_args(args)

    if with_loggers is True:
        if args.verbose is None:
            verbose_level = 0
        else:
            verbose_level = args.verbose
        setup_loggers(verbose_level=verbose_level)

    if args.subcommand == 'proposal' and args.proposal_cmd == 'create':
        _do_config_proposal_create(args)
    elif args.subcommand == 'proposal' and args.proposal_cmd == 'list':
        _do_config_proposal_list(args)
    elif args.subcommand == 'proposal' and args.proposal_cmd == 'vote':
        _do_config_proposal_vote(args)
    elif args.subcommand == 'genesis':
        _do_config_genesis(args)
    else:
        raise CliException('"{}" is not a valid subcommand of "config"'.format(
            args.subcommand))
示例#8
0
def do_cluster_logs(args):
    state = load_state()

    supported_types = 'docker',
    if state['Manage'] in supported_types:
        prefix = 'sawtooth-cluster-0'

        for node_name in args.node_names:
            try:
                node_num = node_name[len('validator-'):]
                processes = state['Processors'] + ['validator']
                containers = [
                    '-'.join([prefix, proc, node_num]) for proc in processes
                ]

                for c in containers:
                    print("Logs for container: " + c + "of node: " + node_name)
                    cmd = ['docker', 'logs', c]
                    handle = subprocess.Popen(cmd)
                    while handle.returncode is None:
                        handle.poll()

            except subprocess.CalledProcessError as cpe:
                raise CliException(str(cpe))
    else:
        print("logs not implemented for {}".format(state['Manage']))
示例#9
0
def do_cluster_status(args):
    state = load_state()

    node_controller = get_node_controller(state, args)
    node_command_generator = SimpleNodeCommandGenerator()
    vnm = ValidatorNetworkManager(
        node_controller=node_controller,
        node_command_generator=node_command_generator)

    if len(args.node_names) > 0:
        node_names = args.node_names
        node_superset = state['Nodes']
        nodes = {}
        for node_name in args.node_names:
            try:
                nodes[node_name] = node_superset[node_name]
            except KeyError:
                raise CliException(
                    "{} is not a known node name".format(node_name))
    else:
        node_names = vnm.get_node_names()
        nodes = state['Nodes']

    # Check expected status of nodes vs what is returned from vnm
    print("NodeName".ljust(15), "Status".ljust(10))
    for node_name in nodes:
        if node_name not in node_names and \
                (nodes[node_name]["Status"] == "Running" or
                    nodes[node_name]["Status"] == "No Response"):
            print(node_name.ljust(15), "Not Running".ljust(10))
        else:
            status = vnm.status(node_name)
            if status == "UNKNOWN":
                status = "Not Running"
            print(node_name.ljust(15), status.ljust(10))
示例#10
0
def main(prog_name=os.path.basename(sys.argv[0]), args=None,
         with_loggers=True):
    parser = create_parser(prog_name)
    if args is None:
        args = sys.argv[1:]
    args = parser.parse_args(args)

    load_cli_config(args)

    if with_loggers is True:
        if args.verbose is None:
            verbose_level = 0
        else:
            verbose_level = args.verbose
        setup_loggers(verbose_level=verbose_level)

    if args.command == 'keygen':
        do_keygen(args)
    elif args.command == 'block':
        do_block(args)
    elif args.command == 'batch':
        do_batch(args)
    elif args.command == 'transaction':
        do_transaction(args)
    elif args.command == 'state':
        do_state(args)
    elif args.command == 'identity':
        do_identity(args)
    elif args.command == 'settings':
        do_settings(args)
    elif args.command == 'peer':
        do_peer(args)
    else:
        raise CliException("invalid command: {}".format(args.command))
示例#11
0
def _read_signing_keys(key_filename):
    """Reads the given file as a WIF formatted key.

    Args:
        key_filename: The filename where the key is stored. If None,
            defaults to the default key for the current user.

    Returns:
        tuple (str, str): the public and private key pair

    Raises:
        CliException: If unable to read the file.
    """
    filename = key_filename
    if filename is None:
        filename = os.path.join(os.path.expanduser('~'), '.sawtooth', 'keys',
                                getpass.getuser() + '.priv')

    try:
        with open(filename, 'r') as key_file:
            signing_key = key_file.read().strip()
            public_key = signing.generate_public_key(signing_key)

            return public_key, signing_key
    except IOError as e:
        raise CliException('Unable to read key file: {}'.format(str(e)))
示例#12
0
def _do_identity_policy_list(args):
    rest_client = RestClient(args.url)
    state = rest_client.list_state(subtree=IDENTITY_NAMESPACE + _POLICY_PREFIX)

    head = state['head']
    state_values = state['data']
    printable_policies = []
    for state_value in state_values:
        policies_list = PolicyList()
        decoded = b64decode(state_value['data'])
        policies_list.ParseFromString(decoded)

        for policy in policies_list.policies:
            printable_policies.append(policy)

    printable_policies.sort(key=lambda p: p.name)

    if args.format == 'default':
        tty_width = tty.width()
        for policy in printable_policies:
            # Set value width to the available terminal space, or the min width
            width = tty_width - len(policy.name) - 3
            width = width if width > _MIN_PRINT_WIDTH else _MIN_PRINT_WIDTH
            value = "Entries:\n"
            for entry in policy.entries:
                entry_string = (" " * 4) + Policy.Type.Name(entry.type) + " " \
                    + entry.key
                value += (entry_string[:width] + '...' if
                          len(entry_string) > width else entry_string) + "\n"
            print('{}: \n  {}'.format(policy.name, value))
    elif args.format == 'csv':
        try:
            writer = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL)
            writer.writerow(['POLICY NAME', 'ENTRIES'])
            for policy in printable_policies:
                output = [policy.name]
                for entry in policy.entries:
                    output.append(
                        Policy.Type.Name(entry.type) + " " + entry.key)
                writer.writerow(output)
        except csv.Error:
            raise CliException('Error writing CSV')
    elif args.format == 'json' or args.format == 'yaml':
        output = {}
        for policy in printable_policies:
            value = "Entries: "
            for entry in policy.entries:
                entry_string = Policy.Type.Name(entry.type) + " " \
                    + entry.key
                value += entry_string + " "
            output[policy.name] = value

        policies_snapshot = {'head': head, 'policies': output}
        if args.format == 'json':
            print(json.dumps(policies_snapshot, indent=2, sort_keys=True))
        else:
            print(yaml.dump(policies_snapshot, default_flow_style=False)[0:-1])
    else:
        raise AssertionError('Unknown format {}'.format(args.format))
示例#13
0
def do_batch(args):
    """Runs the batch list or batch show command, printing output to the console

        Args:
            args: The parsed arguments sent to the command at runtime
    """
    rest_client = RestClient(args.url, args.user)

    if args.subcommand == 'list':
        batches = rest_client.list_batches()
        keys = ('batch_id', 'txns', 'signer')
        headers = tuple(k.upper() for k in keys)

        def parse_batch_row(batch):
            return (batch['header_signature'],
                    len(batch.get('transactions',
                                  [])), batch['header']['signer_pubkey'])

        if args.format == 'default':
            fmt.print_terminal_table(headers, batches, parse_batch_row)

        elif args.format == 'csv':
            fmt.print_csv(headers, batches, parse_batch_row)

        elif args.format == 'json' or args.format == 'yaml':
            data = [{k: d
                     for k, d in zip(keys, parse_batch_row(b))}
                    for b in batches]

            if args.format == 'yaml':
                fmt.print_yaml(data)
            elif args.format == 'json':
                fmt.print_json(data)
            else:
                raise AssertionError('Missing handler: {}'.format(args.format))

        else:
            raise AssertionError('Missing handler: {}'.format(args.format))

    if args.subcommand == 'show':
        output = rest_client.get_batch(args.batch_id)

        if args.key:
            if args.key in output:
                output = output[args.key]
            elif args.key in output['header']:
                output = output['header'][args.key]
            else:
                raise CliException(
                    'key "{}" not found in batch or header'.format(args.key))

        if args.format == 'yaml':
            fmt.print_yaml(output)
        elif args.format == 'json':
            fmt.print_json(output)
        else:
            raise AssertionError('Missing handler: {}'.format(args.format))
示例#14
0
def _do_config_list(args):
    """Lists the current on-chain configuration values.
    """
    rest_client = RestClient(args.url)
    state = rest_client.list_state(subtree=SETTINGS_NAMESPACE)

    prefix = args.filter

    head = state['head']
    state_values = state['data']
    printable_settings = []
    proposals_address = _key_to_address('sawtooth.settings.vote.proposals')
    for state_value in state_values:
        if state_value['address'] == proposals_address:
            # This is completely internal setting and we won't list it here
            continue

        decoded = b64decode(state_value['data'])
        setting = Setting()
        setting.ParseFromString(decoded)

        for entry in setting.entries:
            if entry.key.startswith(prefix):
                printable_settings.append(entry)

    printable_settings.sort(key=lambda s: s.key)

    if args.format == 'default':
        tty_width = tty.width()
        for setting in printable_settings:
            # Set value width to the available terminal space, or the min width
            width = tty_width - len(setting.key) - 3
            width = width if width > _MIN_PRINT_WIDTH else _MIN_PRINT_WIDTH
            value = (setting.value[:width] +
                     '...' if len(setting.value) > width else setting.value)
            print('{}: {}'.format(setting.key, value))
    elif args.format == 'csv':
        try:
            writer = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL)
            writer.writerow(['KEY', 'VALUE'])
            for setting in printable_settings:
                writer.writerow([setting.key, setting.value])
        except csv.Error:
            raise CliException('Error writing CSV')
    elif args.format == 'json' or args.format == 'yaml':
        settings_snapshot = {
            'head': head,
            'settings':
            {setting.key: setting.value
             for setting in printable_settings}
        }
        if args.format == 'json':
            print(json.dumps(settings_snapshot, indent=2, sort_keys=True))
        else:
            print(yaml.dump(settings_snapshot, default_flow_style=False)[0:-1])
    else:
        raise AssertionError('Unknown format {}'.format(args.format))
示例#15
0
 def _get(self, path, **queries):
     code, json_result = self._submit_request(self._base_url + path +
                                              self._format_queries(queries))
     if code == 200:
         return json_result
     elif code == 404:
         return None
     else:
         raise CliException("({}): {}".format(code, json_result))
示例#16
0
def do_admin(args):
    data_dir = ensure_directory('data', '/var/lib/sawtooth')

    if args.admin_cmd == 'genesis':
        do_genesis(args, data_dir)
    elif args.admin_cmd == 'keygen':
        do_keygen(args)
    else:
        raise CliException("invalid command: {}".format(args.admin_cmd))
    def _submit_request(self, url, params=None, data=None, headers=None,
                        method="GET"):
        """Submits the given request, and handles the errors appropriately.

        Args:
            url (str): the request to send.
            params (dict): params to be passed along to get/post
            data (bytes): the data to include in the request.
            headers (dict): the headers to include in the request.
            method (str): the method to use for the request, "POST" or "GET".

        Returns:
            tuple of (int, str): The response status code and the json parsed
                body, or the error message.

        Raises:
            `CliException`: If any issues occur with the URL.
        """
        if headers is None:
            headers = {}

        if self._auth_header is not None:
            headers['Authorization'] = self._auth_header

        try:
            if method == 'POST':
                result = requests.post(
                    url, params=params, data=data, headers=headers)
            elif method == 'GET':
                result = requests.get(
                    url, params=params, data=data, headers=headers)
            result.raise_for_status()
            return (result.status_code, result.json())
        except requests.exceptions.HTTPError as e:
            return (e.response.status_code, e.response.reason)
        except RemoteDisconnected as e:
            raise CliException(e)
        except (requests.exceptions.MissingSchema,
                requests.exceptions.InvalidURL) as e:
            raise CliException(e)
        except requests.exceptions.ConnectionError as e:
            raise CliException(
                ('Unable to connect to "{}": '
                 'make sure URL is correct').format(self._base_url))
示例#18
0
def do_state(args):
    """Runs the batch list or batch show command, printing output to the
    console

        Args:
            args: The parsed arguments sent to the command at runtime
    """
    rest_client = RestClient(args.url, args.user)

    if args.subcommand == 'list':
        response = rest_client.list_state(args.subtree, args.head)
        leaves = response['data']
        head = response['head']
        keys = ('address', 'size', 'data')
        headers = tuple(k.upper() for k in keys)

        def parse_leaf_row(leaf, decode=True):
            decoded = b64decode(leaf['data'])
            return (leaf['address'], len(decoded),
                    str(decoded) if decode else leaf['data'])

        if args.format == 'default':
            fmt.print_terminal_table(headers, leaves, parse_leaf_row)
            print('HEAD BLOCK: "{}"'.format(head))

        elif args.format == 'csv':
            fmt.print_csv(headers, leaves, parse_leaf_row)
            print('(data for head block: "{}")'.format(head))

        elif args.format == 'json' or args.format == 'yaml':
            state_data = {
                'head':
                head,
                'data': [
                    dict(zip(keys, parse_leaf_row(leaf, False)))
                    for leaf in leaves
                ]
            }

            if args.format == 'yaml':
                fmt.print_yaml(state_data)
            elif args.format == 'json':
                fmt.print_json(state_data)
            else:
                raise AssertionError('Missing handler: {}'.format(args.format))

        else:
            raise AssertionError('Missing handler: {}'.format(args.format))

    if args.subcommand == 'show':
        output = rest_client.get_leaf(args.address, args.head)
        if output is not None:
            print('DATA: "{}"'.format(b64decode(output['data'])))
            print('HEAD: "{}"'.format(output['head']))
        else:
            raise CliException('No data available at {}'.format(args.address))
示例#19
0
    def _get_data(self, path, **queries):
        url = self._base_url + path
        while url:
            code, json_result = self._submit_request(
                url,
                params=self._format_queries(queries),
            )

            if code == 404:
                raise CliException(
                    'There is no resource with the identifier "{}"'.
                    format(path.split('/')[-1]))
            elif code != 200:
                raise CliException("({}): {}".format(code, json_result))

            for item in json_result.get('data', []):
                yield item

            url = json_result['paging'].get('next', None)
    def _get_data(self, path, **queries):
        url = self._base_url + path
        params = self._format_queries(queries)

        while url:
            code, json_result = self._submit_request(url, params=params)

            if code == 404:
                raise CliException(
                    '{}: There is no resource with the identifier "{}"'.format(
                        self._base_url,
                        path.split("/")[-1]))
            elif code != 200:
                raise CliException("{}: {} {}".format(self._base_url, code,
                                                      json_result))

            for item in json_result.get("data", []):
                yield item

            url = json_result["paging"].get("next", None)
示例#21
0
def print_csv(headers, data_list, parse_row_fn):
    """Takes headers, data, and a row parsing function, and prints data
    to the console in a csv format.
    """
    try:
        writer = csv.writer(sys.stdout)
        writer.writerow(headers)
        for data in data_list:
            writer.writerow(parse_row_fn(data))
    except csv.Error as e:
        raise CliException('Error writing CSV: {}'.format(e))
示例#22
0
    def _get(self, path, queries=None):
        query_string = '?' + urlencode(queries) if queries else ''

        code, json_result = self._submit_request(self._base_url + path +
                                                 query_string)
        if code == 200:
            return json_result
        elif code == 404:
            return None
        else:
            raise CliException("({}): {}".format(code, json_result))
示例#23
0
    def _get(self, path, **queries):
        code, json_result = self._submit_request(
            self._base_url + path,
            params=self._format_queries(queries),
        )

        # concat any additional pages of data
        while code == 200 and 'next' in json_result.get('paging', {}):
            previous_data = json_result.get('data', [])
            code, json_result = self._submit_request(
                json_result['paging']['next'])
            json_result['data'] = previous_data + json_result.get('data', [])

        if code == 200:
            return json_result
        elif code == 404:
            raise CliException('There is no resource with the identifier "{}"'.
                               format(path.split('/')[-1]))
        else:
            raise CliException("({}): {}".format(code, json_result))
    def _get(self, path, **queries):
        code, json_result = self._submit_request(
            self._base_url + path, params=self._format_queries(queries))

        # concat any additional pages of data
        while code == 200 and "next" in json_result.get("paging", {}):
            previous_data = json_result.get("data", [])
            code, json_result = self._submit_request(
                json_result["paging"]["next"])
            json_result["data"] = previous_data + json_result.get("data", [])

        if code == 200:
            return json_result
        if code == 404:
            raise CliException(
                '{}: There is no resource with the identifier "{}"'.format(
                    self._base_url,
                    path.split("/")[-1]))

        raise CliException("{}: {} {}".format(self._base_url, code,
                                              json_result))
示例#25
0
def _do_config_genesis(args):
    signer = _read_signer(args.key)
    public_key = signer.get_public_key().as_hex()

    authorized_keys = args.authorized_key if args.authorized_key else \
        [public_key]
    if public_key not in authorized_keys:
        authorized_keys.append(public_key)

    txns = []

    txns.append(_create_propose_txn(
        signer,
        ('sawtooth.settings.vote.authorized_keys',
         ','.join(authorized_keys))))

    if args.approval_threshold is not None:
        if args.approval_threshold < 1:
            raise CliException('approval threshold must not be less than 1')

        if args.approval_threshold > len(authorized_keys):
            raise CliException(
                'approval threshold must not be greater than the number of '
                'authorized keys')

        txns.append(_create_propose_txn(
            signer,
            ('sawtooth.settings.vote.approval_threshold',
             str(args.approval_threshold))))

    batch = _create_batch(signer, txns)
    batch_list = BatchList(batches=[batch])

    try:
        with open(args.output, 'wb') as batch_file:
            batch_file.write(batch_list.SerializeToString())
        print('Generated {}'.format(args.output))
    except IOError as e:
        raise CliException(
            'Unable to write to batch file: {}'.format(str(e)))
示例#26
0
    def _submit_request(self, url_or_request):
        """Submits the given request, and handles the errors appropriately.

        Args:
            url_or_request (str or `urlib.request.Request`): the request to
                send.

        Returns:
            `http.client.HTTPResponse`: The response from the request.

        Raises:
            `CliException`: If any issues occur when making the request or the
                URL is unavailable.
        """
        try:
            return urllib.urlopen(url_or_request)
        except HTTPError as e:
            raise CliException('({}) {}'.format(e.code, e.msg))
        except URLError as e:
            raise CliException(
                ('Unable to connect to "{}": '
                 'make sure URL is correct').format(self._base_url))
示例#27
0
def _do_identity_role_create(args):
    """Executes the 'role create' subcommand.  Given a key file, a role name,
    and a policy name it generates a batch of sawtooth_identity
    transactions in a BatchList instance. The BatchList is either stored to a
    file or submitted to a validator, depending on the supplied CLI arguments.
    """
    signer = _read_signer(args.key)
    txns = [_create_role_txn(signer, args.name,
                             args.policy)]

    batch = _create_batch(signer, txns)

    batch_list = BatchList(batches=[batch])

    if args.output is not None:
        try:
            with open(args.output, 'wb') as batch_file:
                batch_file.write(batch_list.SerializeToString())
        except IOError as e:
            raise CliException(
                'Unable to write to batch file: {}'.format(str(e)))
    elif args.url is not None:
        rest_client = RestClient(args.url)
        rest_client.send_batches(batch_list)
        if args.wait and args.wait > 0:
            batch_id = batch.header_signature
            wait_time = 0
            start_time = time.time()

            while wait_time < args.wait:
                statuses = rest_client.get_statuses(
                    [batch_id],
                    args.wait - int(wait_time))
                wait_time = time.time() - start_time

                if statuses[0]['status'] == 'COMMITTED':
                    print(
                        'Role committed in {:.6} sec'.format(wait_time))
                    return

                # Wait a moment so as not to hammer the Rest Api
                time.sleep(0.2)

            print('Wait timed out! Role was not committed...')
            print('{:128.128}  {}'.format(
                batch_id,
                statuses[0]['status']))
            exit(1)
    else:
        raise AssertionError('No target for create set.')
示例#28
0
def do_cluster(args):
    if args.cluster_command == 'start':
        do_cluster_start(args)
    elif args.cluster_command == 'status':
        do_cluster_status(args)
    elif args.cluster_command == 'stop':
        do_cluster_stop(args)
    elif args.cluster_command == 'extend':
        do_cluster_extend(args)
    elif args.cluster_command == 'logs':
        do_cluster_logs(args)
    else:
        raise CliException("invalid cluster command: {}".format(
            args.cluster_command))
示例#29
0
def _read_signer(key_filename):
    """Reads the given file as a hex, or (as a fallback) a WIF formatted key.

    Args:
        key_filename: The filename where the key is stored. If None,
            defaults to the default key for the current user.

    Returns:
        Signer: the signer

    Raises:
        CliException: If unable to read the file.
    """
    filename = key_filename
    if filename is None:
        filename = os.path.join(os.path.expanduser('~'),
                                '.sawtooth',
                                'keys',
                                getpass.getuser() + '.priv')

    try:
        with open(filename, 'r') as key_file:
            signing_key = key_file.read().strip()
    except IOError as e:
        raise CliException('Unable to read key file: {}'.format(str(e)))

    try:
        private_key = Secp256k1PrivateKey.from_hex(signing_key)
    except ParseError as e:
        try:
            private_key = Secp256k1PrivateKey.from_wif(signing_key)
        except ParseError:
            raise CliException('Unable to read key in file: {}'.format(str(e)))

    context = create_context('secp256k1')
    crypto_factory = CryptoFactory(context)
    return crypto_factory.new_signer(private_key)
示例#30
0
def _do_identity_role_list(args):
    """Lists the current on-chain configuration values.
    """
    rest_client = RestClient(args.url)
    state = rest_client.list_state(subtree=IDENTITY_NAMESPACE + _ROLE_PREFIX)

    head = state['head']
    state_values = state['data']
    printable_roles = []
    for state_value in state_values:
        role_list = RoleList()
        decoded = b64decode(state_value['data'])
        role_list.ParseFromString(decoded)

        for role in role_list.roles:
            printable_roles.append(role)

    printable_roles.sort(key=lambda r: r.name)

    if args.format == 'default':
        tty_width = tty.width()
        for role in printable_roles:
            # Set value width to the available terminal space, or the min width
            width = tty_width - len(role.name) - 3
            width = width if width > _MIN_PRINT_WIDTH else _MIN_PRINT_WIDTH
            value = (role.policy_name[:width] + '...'
                     if len(role.policy_name) > width
                     else role.policy_name)
            print('{}: {}'.format(role.name, value))
    elif args.format == 'csv':
        try:
            writer = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL)
            writer.writerow(['KEY', 'VALUE'])
            for role in printable_roles:
                writer.writerow([role.name, role.policy_name])
        except csv.Error:
            raise CliException('Error writing CSV')
    elif args.format == 'json' or args.format == 'yaml':
        roles_snapshot = {
            'head': head,
            'roles': {role.name: role.policy_name
                      for role in printable_roles}
        }
        if args.format == 'json':
            print(json.dumps(roles_snapshot, indent=2, sort_keys=True))
        else:
            print(yaml.dump(roles_snapshot, default_flow_style=False)[0:-1])
    else:
        raise AssertionError('Unknown format {}'.format(args.format))