1# -*- coding: utf-8 -*- #
2# Copyright 2019 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"""Service Consumer Management API helper functions."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import unicode_literals
20
21from apitools.base.py import exceptions as apitools_exceptions
22from apitools.base.py import list_pager
23from googlecloudsdk.api_lib.services import exceptions
24from googlecloudsdk.api_lib.util import apis
25
26_SERVICE_CONSUMER_RESOURCE = 'services/%s/%s'
27_LIMIT_OVERRIDE_RESOURCE = '%s/producerOverrides/%s'
28
29
30def ListQuotaMetrics(service, consumer, page_size=None, limit=None):
31  """List service quota metrics for a consumer.
32
33  Args:
34    service: The service to list metrics for.
35    consumer: The consumer to list metrics for, e.g. "projects/123".
36    page_size: The page size to list.
37    limit: The max number of metrics to return.
38
39  Raises:
40    exceptions.PermissionDeniedException: when listing metrics fails.
41    apitools_exceptions.HttpError: Another miscellaneous error with the service.
42
43  Returns:
44    The list of quota metrics
45  """
46  client = _GetClientInstance()
47  messages = client.MESSAGES_MODULE
48
49  request = messages.ServiceconsumermanagementServicesConsumerQuotaMetricsListRequest(
50      parent=_SERVICE_CONSUMER_RESOURCE % (service, consumer))
51  return list_pager.YieldFromList(
52      client.services_consumerQuotaMetrics,
53      request,
54      limit=limit,
55      batch_size_attribute='pageSize',
56      batch_size=page_size,
57      field='metrics')
58
59
60def UpdateQuotaOverrideCall(service,
61                            consumer,
62                            metric,
63                            unit,
64                            dimensions,
65                            value,
66                            force=False):
67  """Update a quota override.
68
69  Args:
70    service: The service to update a quota override for.
71    consumer: The consumer to update a quota override for, e.g. "projects/123".
72    metric: The quota metric name.
73    unit: The unit of quota metric.
74    dimensions: The dimensions of the override in dictionary format. It can be
75      None.
76    value: The override integer value.
77    force: Force override update even if the change results in a substantial
78      decrease in available quota.
79
80  Raises:
81    exceptions.UpdateQuotaOverridePermissionDeniedException: when updating an
82    override fails.
83    apitools_exceptions.HttpError: Another miscellaneous error with the service.
84
85  Returns:
86    The quota override operation.
87  """
88  client = _GetClientInstance()
89  messages = client.MESSAGES_MODULE
90
91  dimensions_message = _GetDimensions(messages, dimensions)
92  request = messages.ServiceconsumermanagementServicesConsumerQuotaMetricsImportProducerOverridesRequest(
93      parent=_SERVICE_CONSUMER_RESOURCE % (service, consumer),
94      v1Beta1ImportProducerOverridesRequest=messages
95      .V1Beta1ImportProducerOverridesRequest(
96          inlineSource=messages.V1Beta1OverrideInlineSource(
97              overrides=[
98                  messages.V1Beta1QuotaOverride(
99                      metric=metric,
100                      unit=unit,
101                      overrideValue=value,
102                      dimensions=dimensions_message)
103              ],),
104          force=force),
105  )
106  try:
107    return client.services_consumerQuotaMetrics.ImportProducerOverrides(request)
108  except (apitools_exceptions.HttpForbiddenError,
109          apitools_exceptions.HttpNotFoundError) as e:
110    exceptions.ReraiseError(
111        e, exceptions.UpdateQuotaOverridePermissionDeniedException)
112
113
114def DeleteQuotaOverrideCall(service,
115                            consumer,
116                            metric,
117                            unit,
118                            override_id,
119                            force=False):
120  """Delete a quota override.
121
122  Args:
123    service: The service to delete a quota aoverride for.
124    consumer: The consumer to delete a quota override for, e.g. "projects/123".
125    metric: The quota metric name.
126    unit: The unit of quota metric.
127    override_id: The override ID.
128    force: Force override deletion even if the change results in a substantial
129      decrease in available quota.
130
131  Raises:
132    exceptions.DeleteQuotaOverridePermissionDeniedException: when deleting an
133    override fails.
134    apitools_exceptions.HttpError: Another miscellaneous error with the service.
135
136  Returns:
137    The quota override operation.
138  """
139  client = _GetClientInstance()
140  messages = client.MESSAGES_MODULE
141
142  parent = _GetMetricResourceName(service, consumer, metric, unit)
143  name = _LIMIT_OVERRIDE_RESOURCE % (parent, override_id)
144  request = messages.ServiceconsumermanagementServicesConsumerQuotaMetricsLimitsProducerOverridesDeleteRequest(
145      name=name,
146      force=force,
147  )
148  try:
149    return client.services_consumerQuotaMetrics_limits_producerOverrides.Delete(
150        request)
151  except (apitools_exceptions.HttpForbiddenError,
152          apitools_exceptions.HttpNotFoundError) as e:
153    exceptions.ReraiseError(
154        e, exceptions.DeleteQuotaOverridePermissionDeniedException)
155
156
157def _GetDimensions(messages, dimensions):
158  if dimensions is None:
159    return None
160  dt = messages.V1Beta1QuotaOverride.DimensionsValue
161  # sorted by key strings to maintain the unit test behavior consistency.
162  return dt(
163      additionalProperties=[
164          dt.AdditionalProperty(key=k, value=dimensions[k])
165          for k in sorted(dimensions.keys())
166      ],)
167
168
169def _GetMetricResourceName(service, consumer, metric, unit):
170  """Get the metric resource name from metric name and unit.
171
172  Args:
173    service: The service to manage an override for.
174    consumer: The consumer to manage an override for, e.g. "projects/123".
175    metric: The quota metric name.
176    unit: The unit of quota metric.
177
178  Raises:
179    exceptions.Error: when the limit with given metric and unit is not found.
180
181  Returns:
182    The quota override operation.
183  """
184  metrics = ListQuotaMetrics(service, consumer)
185  for m in metrics:
186    if m.metric == metric:
187      for q in m.consumerQuotaLimits:
188        if q.unit == unit:
189          return q.name
190  raise exceptions.Error('limit not found with name "%s" and unit "%s".' %
191                         (metric, unit))
192
193
194def GetOperation(name):
195  """Make API call to get an operation.
196
197  Args:
198    name: The name of the operation.
199
200  Raises:
201    exceptions.OperationErrorException: when the getting operation API fails.
202    apitools_exceptions.HttpError: Another miscellaneous error with the service.
203
204  Returns:
205    The result of the operation
206  """
207  client = _GetClientInstance()
208  messages = client.MESSAGES_MODULE
209  request = messages.ServiceconsumermanagementOperationsGetRequest(name=name)
210  try:
211    return client.operations.Get(request)
212  except (apitools_exceptions.HttpForbiddenError,
213          apitools_exceptions.HttpNotFoundError) as e:
214    exceptions.ReraiseError(e, exceptions.OperationErrorException)
215
216
217def _GetClientInstance():
218  return apis.GetClientInstance('serviceconsumermanagement', 'v1beta1')
219