github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/gubernator/pb_glance.py (about)

     1  #!/usr/bin/env python
     2  # Copyright 2016 The Kubernetes Authors.
     3  #
     4  # Licensed under the Apache License, Version 2.0 (the "License");
     5  # you may not use this file except in compliance with the License.
     6  # You may obtain a copy of the License at
     7  #
     8  #     http://www.apache.org/licenses/LICENSE-2.0
     9  #
    10  # Unless required by applicable law or agreed to in writing, software
    11  # distributed under the License is distributed on an "AS IS" BASIS,
    12  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  # See the License for the specific language governing permissions and
    14  # limitations under the License.
    15  
    16  '''
    17  A tiny, minimal protobuf2 parser that's able to extract enough information
    18  to be useful.
    19  '''
    20  
    21  import cStringIO as StringIO
    22  
    23  
    24  def parse_protobuf(data, schema=None):
    25      '''
    26      Do a simple parse of a protobuf2 given minimal type information.
    27  
    28      Args:
    29          data: a string containing the encoded protocol buffer.
    30          schema: a dict containing information about each field number.
    31              The keys are field numbers, and the values represent:
    32                  - str: the name of the field
    33                  - dict: schema to recursively decode an embedded message.
    34                          May contain a 'name' key to name the field.
    35      Returns:
    36          dict: mapping from fields to values. The fields may be strings instead of
    37              numbers if schema named them, and the value will *always* be
    38              a list of values observed for that key.
    39      '''
    40      if schema is None:
    41          schema = {}
    42  
    43      buf = StringIO.StringIO(data)
    44  
    45      def read_varint():
    46          out = 0
    47          shift = 0
    48          c = 0x80
    49          while c & 0x80:
    50              c = ord(buf.read(1))
    51              out = out | ((c & 0x7f) << shift)
    52              shift += 7
    53          return out
    54  
    55      values = {}
    56  
    57      while buf.tell() < len(data):
    58          key = read_varint()
    59          wire_type = key & 0b111
    60          field_number = key >> 3
    61          field_name = field_number
    62          if wire_type == 0:
    63              value = read_varint()
    64          elif wire_type == 1:  # 64-bit
    65              value = buf.read(8)
    66          elif wire_type == 2:  # length-delim
    67              length = read_varint()
    68              value = buf.read(length)
    69              if isinstance(schema.get(field_number), basestring):
    70                  field_name = schema[field_number]
    71              elif field_number in schema:
    72                  # yes, I'm using dynamic features of a dynamic language.
    73                  # pylint: disable=redefined-variable-type
    74                  value = parse_protobuf(value, schema[field_number])
    75                  field_name = schema[field_number].get('name', field_name)
    76          elif wire_type == 5:  # 32-bit
    77              value = buf.read(4)
    78          else:
    79              raise ValueError('unhandled wire type %d' % wire_type)
    80          values.setdefault(field_name, []).append(value)
    81  
    82      return values