github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/cli/sawtooth_cli/settings.py (about)

     1  # Copyright 2017 Intel Corporation
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #     http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  # ------------------------------------------------------------------------------
    15  
    16  from base64 import b64decode
    17  import csv
    18  import hashlib
    19  import json
    20  import sys
    21  
    22  import yaml
    23  
    24  from sawtooth_cli.exceptions import CliException
    25  from sawtooth_cli.rest_client import RestClient
    26  from sawtooth_cli import tty
    27  
    28  from sawtooth_cli.protobuf.setting_pb2 import Setting
    29  
    30  
    31  SETTINGS_NAMESPACE = '000000'
    32  
    33  _MIN_PRINT_WIDTH = 15
    34  _MAX_KEY_PARTS = 4
    35  _ADDRESS_PART_SIZE = 16
    36  
    37  
    38  def add_settings_parser(subparsers, parent_parser):
    39      """Creates the args parser needed for the settings command and its
    40      subcommands.
    41      """
    42      # The following parser is for the settings subsection of commands.  These
    43      # commands display information about the currently applied on-chain
    44      # settings.
    45  
    46      settings_parser = subparsers.add_parser(
    47          'settings',
    48          help='Displays on-chain settings',
    49          description='Displays the values of currently active on-chain '
    50                      'settings.')
    51  
    52      settings_parsers = settings_parser.add_subparsers(
    53          title='settings',
    54          dest='settings_cmd')
    55      settings_parsers.required = True
    56  
    57      list_parser = settings_parsers.add_parser(
    58          'list',
    59          help='Lists the current keys and values of on-chain settings',
    60          description='List the current keys and values of on-chain '
    61                      'settings. The content can be exported to various '
    62                      'formats for external consumption.'
    63      )
    64  
    65      list_parser.add_argument(
    66          '--url',
    67          type=str,
    68          help="identify the URL of a validator's REST API",
    69          default='http://localhost:8008')
    70  
    71      list_parser.add_argument(
    72          '--filter',
    73          type=str,
    74          default='',
    75          help='filters keys that begin with this value')
    76  
    77      list_parser.add_argument(
    78          '--format',
    79          default='default',
    80          choices=['default', 'csv', 'json', 'yaml'],
    81          help='choose the output format')
    82  
    83  
    84  def do_settings(args):
    85      if args.settings_cmd == 'list':
    86          _do_settings_list(args)
    87      else:
    88          raise AssertionError('Invalid subcommand: ')
    89  
    90  
    91  def _do_settings_list(args):
    92      """Lists the current on-chain configuration values.
    93      """
    94      rest_client = RestClient(args.url)
    95      state = rest_client.list_state(subtree=SETTINGS_NAMESPACE)
    96  
    97      prefix = args.filter
    98  
    99      head = state['head']
   100      state_values = state['data']
   101      printable_settings = []
   102      proposals_address = _key_to_address('sawtooth.settings.vote.proposals')
   103      for state_value in state_values:
   104          if state_value['address'] == proposals_address:
   105              # This is completely internal setting and we won't list it here
   106              continue
   107  
   108          decoded = b64decode(state_value['data'])
   109          setting = Setting()
   110          setting.ParseFromString(decoded)
   111  
   112          for entry in setting.entries:
   113              if entry.key.startswith(prefix):
   114                  printable_settings.append(entry)
   115  
   116      printable_settings.sort(key=lambda s: s.key)
   117  
   118      if args.format == 'default':
   119          tty_width = tty.width()
   120          for setting in printable_settings:
   121              # Set value width to the available terminal space, or the min width
   122              width = tty_width - len(setting.key) - 3
   123              width = width if width > _MIN_PRINT_WIDTH else _MIN_PRINT_WIDTH
   124              value = (setting.value[:width] + '...'
   125                       if len(setting.value) > width
   126                       else setting.value)
   127              print('{}: {}'.format(setting.key, value))
   128      elif args.format == 'csv':
   129          try:
   130              writer = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL)
   131              writer.writerow(['KEY', 'VALUE'])
   132              for setting in printable_settings:
   133                  writer.writerow([setting.key, setting.value])
   134          except csv.Error:
   135              raise CliException('Error writing CSV')
   136      elif args.format == 'json' or args.format == 'yaml':
   137          settings_snapshot = {
   138              'head': head,
   139              'settings': {setting.key: setting.value
   140                           for setting in printable_settings}
   141          }
   142          if args.format == 'json':
   143              print(json.dumps(settings_snapshot, indent=2, sort_keys=True))
   144          else:
   145              print(yaml.dump(settings_snapshot, default_flow_style=False)[0:-1])
   146      else:
   147          raise AssertionError('Unknown format {}'.format(args.format))
   148  
   149  
   150  def _key_to_address(key):
   151      """Creates the state address for a given setting key.
   152      """
   153      key_parts = key.split('.', maxsplit=_MAX_KEY_PARTS - 1)
   154      key_parts.extend([''] * (_MAX_KEY_PARTS - len(key_parts)))
   155  
   156      return SETTINGS_NAMESPACE + ''.join(_short_hash(x) for x in key_parts)
   157  
   158  
   159  def _short_hash(in_str):
   160      return hashlib.sha256(in_str.encode()).hexdigest()[:_ADDRESS_PART_SIZE]