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