1# -*- coding: utf-8 -*- # 2# Copyright 2016 Google LLC. All Rights Reserved. 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"""Debug resource transforms and symbols dict. 17 18NOTICE: Each TransformFoo() method is the implementation of a foo() transform 19function. Even though the implementation here is in Python the usage in resource 20projection and filter expressions is language agnostic. This affects the 21Pythonicness of the Transform*() methods: 22 (1) The docstrings are used to generate external user documentation. 23 (2) The method prototypes are included in the documentation. In particular the 24 prototype formal parameter names are stylized for the documentation. 25 (3) The types of some args, like r, are not fixed until runtime. Other args 26 may have either a base type value or string representation of that type. 27 It is up to the transform implementation to silently do the string=>type 28 conversions. That's why you may see e.g. int(arg) in some of the methods. 29 (4) Unless it is documented to do so, a transform function must not raise any 30 exceptions. The `undefined' arg is used to handle all unusual conditions, 31 including ones that would raise exceptions. 32""" 33 34from __future__ import absolute_import 35from __future__ import division 36from __future__ import unicode_literals 37 38import re 39 40 41def TransformFullStatus(r, undefined='UNKNOWN_ERROR'): 42 """Returns a full description of the status of a logpoint or snapshot. 43 44 Status will be one of ACTIVE, COMPLETED, or a verbose error description. If 45 the status is an error, there will be additional information available in the 46 status field of the object. 47 48 Args: 49 r: a JSON-serializable object 50 undefined: Returns this value if the resource is not a valid status. 51 52 Returns: 53 One of ACTIVE, COMPLETED, or a verbose error description. 54 55 Example: 56 `--format="table(id, location, full_status())"`::: 57 Displays the full status in the third table problem. 58 """ 59 short_status, full_status = _TransformStatuses(r, undefined) 60 if full_status: 61 return '{0}: {1}'.format(short_status, full_status) 62 else: 63 return short_status 64 65 66def TransformShortStatus(r, undefined='UNKNOWN_ERROR'): 67 """Returns a short description of the status of a logpoint or snapshot. 68 69 Status will be one of ACTIVE, COMPLETED, or a short error description. If 70 the status is an error, there will be additional information available in the 71 status field of the object. 72 73 Args: 74 r: a JSON-serializable object 75 undefined: Returns this value if the resource is not a valid status. 76 77 Returns: 78 One of ACTIVE, COMPLETED, or an error description. 79 80 Example: 81 `--format="table(id, location, short_status())"`::: 82 Displays the short status in the third table problem. 83 """ 84 short_status, _ = _TransformStatuses(r, undefined) 85 return short_status 86 87 88def _TransformStatuses(r, undefined): 89 """Returns a full description of the status of a logpoint or snapshot. 90 91 Status will be one of ACTIVE, COMPLETED, or a verbose error description. If 92 the status is an error, there will be additional information available in the 93 status field of the object. 94 95 Args: 96 r: a JSON-serializable object 97 undefined: Returns this value if the resource is not a valid status. 98 99 Returns: 100 String, String - The first string will be a short error description, 101 and the second a more detailed description. 102 """ 103 short_status = undefined 104 if isinstance(r, dict): 105 if not r.get('isFinalState'): 106 return 'ACTIVE', None 107 status = r.get('status') 108 if not status or not isinstance(status, dict) or not status.get('isError'): 109 return 'COMPLETED', None 110 refers_to = status.get('refersTo') 111 description = status.get('description') 112 if refers_to: 113 short_status = '{0}_ERROR'.format(refers_to).replace('BREAKPOINT_', '') 114 if description: 115 fmt = description.get('format') 116 params = description.get('parameters') or [] 117 try: 118 return short_status, _SubstituteErrorParams(fmt, params) 119 except (IndexError, KeyError): 120 return short_status, 'Malformed status message: {0}'.format(status) 121 return short_status, None 122 123 124def _SubstituteErrorParams(fmt, params): 125 """Replaces $N with the Nth param in fmt. 126 127 Args: 128 fmt: A format string which may contain substitutions of the form $N, where 129 N is any decimal integer between 0 and len(params) - 1. 130 params: A set of parameters to substitute in place of the $N string. 131 Returns: 132 A string containing fmt with each $N substring replaced with its 133 corresponding parameter. 134 """ 135 if not params: 136 return fmt 137 return re.sub(r'\$([0-9]+)', r'{\1}', fmt).format(*params) 138 139 140_TRANSFORMS = { 141 'full_status': TransformFullStatus, 142 'short_status': TransformShortStatus, 143} 144 145 146def GetTransforms(): 147 """Returns the debug specific resource transform symbol table.""" 148 return _TRANSFORMS 149