Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: third_party/google-endpoints/google/api/control/operation.py

Issue 2666783008: Add google-endpoints to third_party/. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2016 Google Inc. All Rights Reserved.
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 """operation provides support for working with `Operation` instances.
16
17 :class:`~google.api.gen.servicecontrol_v1_message.Operation` represents
18 information regarding an operation, and is a key constituent of
19 :class:`~google.api.gen.servicecontrol_v1_message.CheckRequest` and
20 :class:`~google.api.gen.servicecontrol_v1_message.ReportRequests.
21
22 The :class:`.Aggregator` support this.
23
24 """
25
26 from __future__ import absolute_import
27
28 import collections
29 import logging
30 from datetime import datetime
31
32 from apitools.base.py import encoding
33
34 from . import messages, metric_value, timestamp, MetricKind
35
36 logger = logging.getLogger(__name__)
37
38
39 class Info(
40 collections.namedtuple(
41 'Info', [
42 'api_key',
43 'api_key_valid',
44 'consumer_project_id',
45 'operation_id',
46 'operation_name',
47 'referer',
48 'service_name',
49 ])):
50 """Holds basic information about an api call.
51
52 This class is one of several used to mediate between the raw service
53 control api surface and python frameworks. Client code can construct
54 operations using this surface
55
56 Attributes:
57 api_key (string): the api key
58 api_key_valid (bool): it the request has a valid api key. By default
59 it is true, it will only be set to false if the api key cannot
60 be validated by the service controller
61 consumer_project_id (string): the project id of the api consumer
62 operation_id (string): identity of the operation, which must be unique
63 within the scope of the service. Calls to report and check on the
64 same operation should carry the same operation id
65 operation_name (string): the fully-qualified name of the operation
66 referer (string): the referer header, or if not present the origin
67 service_name(string): the name of service
68
69 """
70 # pylint: disable=too-many-arguments
71
72 def __new__(cls,
73 api_key='',
74 api_key_valid=False,
75 consumer_project_id='',
76 operation_id='',
77 operation_name='',
78 referer='',
79 service_name=''):
80 """Invokes the base constructor with default values."""
81 return super(cls, Info).__new__(
82 cls,
83 api_key,
84 api_key_valid,
85 consumer_project_id,
86 operation_id,
87 operation_name,
88 referer,
89 service_name)
90
91 def as_operation(self, timer=datetime.utcnow):
92 """Makes an ``Operation`` from this instance.
93
94 Returns:
95 an ``Operation``
96
97 """
98 now = timer()
99 op = messages.Operation(
100 endTime=timestamp.to_rfc3339(now),
101 startTime=timestamp.to_rfc3339(now),
102 importance=messages.Operation.ImportanceValueValuesEnum.LOW)
103 if self.operation_id:
104 op.operationId = self.operation_id
105 if self.operation_name:
106 op.operationName = self.operation_name
107 if self.api_key and self.api_key_valid:
108 op.consumerId = 'api_key:' + self.api_key
109 elif self.consumer_project_id:
110 op.consumerId = 'project:' + self.consumer_project_id
111 return op
112
113
114 class Aggregator(object):
115 """Container that implements operation aggregation.
116
117 Thread compatible.
118 """
119 DEFAULT_KIND = MetricKind.DELTA
120 """Used when kinds are not specified, or are missing a metric name"""
121
122 def __init__(self, initial_op, kinds=None):
123 """Constructor.
124
125 If kinds is not specifed, all operations will be merged assuming
126 they are of Kind ``DEFAULT_KIND``
127
128 Args:
129 initial_op (
130 :class:`google.api.gen.servicecontrol_v1_messages.Operation`): the
131 initial version of the operation
132 kinds (dict[string,[string]]): specifies the metric kind for
133 each metric name
134
135 """
136 assert isinstance(initial_op, messages.Operation)
137 if kinds is None:
138 kinds = {}
139 self._kinds = kinds
140 self._metric_values_by_name_then_sign = collections.defaultdict(dict)
141 our_op = encoding.CopyProtoMessage(initial_op)
142 self._merge_metric_values(our_op)
143 our_op.metricValueSets = []
144 self._op = our_op
145
146 def as_operation(self):
147 """Obtains a single `Operation` representing this instances contents.
148
149 Returns:
150 :class:`google.api.gen.servicecontrol_v1_messages.Operation`
151 """
152 result = encoding.CopyProtoMessage(self._op)
153 names = sorted(self._metric_values_by_name_then_sign.keys())
154 for name in names:
155 mvs = self._metric_values_by_name_then_sign[name]
156 result.metricValueSets.append(
157 messages.MetricValueSet(
158 metricName=name, metricValues=mvs.values()))
159 return result
160
161 def add(self, other_op):
162 """Combines `other_op` with the operation held by this aggregator.
163
164 N.B. It merges the operations log entries and metric values, but makes
165 the assumption the operation is consistent. It's the callers
166 responsibility to ensure consistency
167
168 Args:
169 other_op (
170 class:`google.api.gen.servicecontrol_v1_messages.Operation`):
171 an operation merge into this one
172
173 """
174 self._op.logEntries.extend(other_op.logEntries)
175 self._merge_timestamps(other_op)
176 self._merge_metric_values(other_op)
177
178 def _merge_metric_values(self, other_op):
179 for value_set in other_op.metricValueSets:
180 name = value_set.metricName
181 kind = self._kinds.get(name, self.DEFAULT_KIND)
182 by_signature = self._metric_values_by_name_then_sign[name]
183 for mv in value_set.metricValues:
184 signature = metric_value.sign(mv)
185 prior = by_signature.get(signature)
186 if prior is not None:
187 metric_value.merge(kind, prior, mv)
188 by_signature[signature] = mv
189
190 def _merge_timestamps(self, other_op):
191 # Update the start time and end time in self._op as needed
192 if (other_op.startTime and
193 (self._op.startTime is None or
194 timestamp.compare(other_op.startTime, self._op.startTime) == -1)):
195 self._op.startTime = other_op.startTime
196
197 if (other_op.endTime and
198 (self._op.endTime is None or timestamp.compare(
199 self._op.endTime, other_op.endTime) == -1)):
200 self._op.endTime = other_op.endTime
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698