1# -*- coding: utf-8 -*-
2# Copyright 2023 Google LLC
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#
16from collections import OrderedDict
17import os
18import re
19from typing import (
20 Dict,
21 Mapping,
22 MutableMapping,
23 MutableSequence,
24 Optional,
25 Sequence,
26 Tuple,
27 Type,
28 Union,
29 cast,
30)
31
32from google.cloud.errorreporting_v1beta1 import gapic_version as package_version
33
34from google.api_core import client_options as client_options_lib
35from google.api_core import exceptions as core_exceptions
36from google.api_core import gapic_v1
37from google.api_core import retry as retries
38from google.auth import credentials as ga_credentials # type: ignore
39from google.auth.transport import mtls # type: ignore
40from google.auth.transport.grpc import SslCredentials # type: ignore
41from google.auth.exceptions import MutualTLSChannelError # type: ignore
42from google.oauth2 import service_account # type: ignore
43
44try:
45 OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault]
46except AttributeError: # pragma: NO COVER
47 OptionalRetry = Union[retries.Retry, object] # type: ignore
48
49from google.cloud.errorreporting_v1beta1.types import common
50from google.cloud.errorreporting_v1beta1.types import error_group_service
51from .transports.base import ErrorGroupServiceTransport, DEFAULT_CLIENT_INFO
52from .transports.grpc import ErrorGroupServiceGrpcTransport
53from .transports.grpc_asyncio import ErrorGroupServiceGrpcAsyncIOTransport
54from .transports.rest import ErrorGroupServiceRestTransport
55
56
57class ErrorGroupServiceClientMeta(type):
58 """Metaclass for the ErrorGroupService client.
59
60 This provides class-level methods for building and retrieving
61 support objects (e.g. transport) without polluting the client instance
62 objects.
63 """
64
65 _transport_registry = (
66 OrderedDict()
67 ) # type: Dict[str, Type[ErrorGroupServiceTransport]]
68 _transport_registry["grpc"] = ErrorGroupServiceGrpcTransport
69 _transport_registry["grpc_asyncio"] = ErrorGroupServiceGrpcAsyncIOTransport
70 _transport_registry["rest"] = ErrorGroupServiceRestTransport
71
72 def get_transport_class(
73 cls,
74 label: Optional[str] = None,
75 ) -> Type[ErrorGroupServiceTransport]:
76 """Returns an appropriate transport class.
77
78 Args:
79 label: The name of the desired transport. If none is
80 provided, then the first transport in the registry is used.
81
82 Returns:
83 The transport class to use.
84 """
85 # If a specific transport is requested, return that one.
86 if label:
87 return cls._transport_registry[label]
88
89 # No transport is requested; return the default (that is, the first one
90 # in the dictionary).
91 return next(iter(cls._transport_registry.values()))
92
93
94class ErrorGroupServiceClient(metaclass=ErrorGroupServiceClientMeta):
95 """Service for retrieving and updating individual error groups."""
96
97 @staticmethod
98 def _get_default_mtls_endpoint(api_endpoint):
99 """Converts api endpoint to mTLS endpoint.
100
101 Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to
102 "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively.
103 Args:
104 api_endpoint (Optional[str]): the api endpoint to convert.
105 Returns:
106 str: converted mTLS api endpoint.
107 """
108 if not api_endpoint:
109 return api_endpoint
110
111 mtls_endpoint_re = re.compile(
112 r"(?P<name>[^.]+)(?P<mtls>\.mtls)?(?P<sandbox>\.sandbox)?(?P<googledomain>\.googleapis\.com)?"
113 )
114
115 m = mtls_endpoint_re.match(api_endpoint)
116 name, mtls, sandbox, googledomain = m.groups()
117 if mtls or not googledomain:
118 return api_endpoint
119
120 if sandbox:
121 return api_endpoint.replace(
122 "sandbox.googleapis.com", "mtls.sandbox.googleapis.com"
123 )
124
125 return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com")
126
127 DEFAULT_ENDPOINT = "clouderrorreporting.googleapis.com"
128 DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore
129 DEFAULT_ENDPOINT
130 )
131
132 @classmethod
133 def from_service_account_info(cls, info: dict, *args, **kwargs):
134 """Creates an instance of this client using the provided credentials
135 info.
136
137 Args:
138 info (dict): The service account private key info.
139 args: Additional arguments to pass to the constructor.
140 kwargs: Additional arguments to pass to the constructor.
141
142 Returns:
143 ErrorGroupServiceClient: The constructed client.
144 """
145 credentials = service_account.Credentials.from_service_account_info(info)
146 kwargs["credentials"] = credentials
147 return cls(*args, **kwargs)
148
149 @classmethod
150 def from_service_account_file(cls, filename: str, *args, **kwargs):
151 """Creates an instance of this client using the provided credentials
152 file.
153
154 Args:
155 filename (str): The path to the service account private key json
156 file.
157 args: Additional arguments to pass to the constructor.
158 kwargs: Additional arguments to pass to the constructor.
159
160 Returns:
161 ErrorGroupServiceClient: The constructed client.
162 """
163 credentials = service_account.Credentials.from_service_account_file(filename)
164 kwargs["credentials"] = credentials
165 return cls(*args, **kwargs)
166
167 from_service_account_json = from_service_account_file
168
169 @property
170 def transport(self) -> ErrorGroupServiceTransport:
171 """Returns the transport used by the client instance.
172
173 Returns:
174 ErrorGroupServiceTransport: The transport used by the client
175 instance.
176 """
177 return self._transport
178
179 @staticmethod
180 def error_group_path(
181 project: str,
182 group: str,
183 ) -> str:
184 """Returns a fully-qualified error_group string."""
185 return "projects/{project}/groups/{group}".format(
186 project=project,
187 group=group,
188 )
189
190 @staticmethod
191 def parse_error_group_path(path: str) -> Dict[str, str]:
192 """Parses a error_group path into its component segments."""
193 m = re.match(r"^projects/(?P<project>.+?)/groups/(?P<group>.+?)$", path)
194 return m.groupdict() if m else {}
195
196 @staticmethod
197 def common_billing_account_path(
198 billing_account: str,
199 ) -> str:
200 """Returns a fully-qualified billing_account string."""
201 return "billingAccounts/{billing_account}".format(
202 billing_account=billing_account,
203 )
204
205 @staticmethod
206 def parse_common_billing_account_path(path: str) -> Dict[str, str]:
207 """Parse a billing_account path into its component segments."""
208 m = re.match(r"^billingAccounts/(?P<billing_account>.+?)$", path)
209 return m.groupdict() if m else {}
210
211 @staticmethod
212 def common_folder_path(
213 folder: str,
214 ) -> str:
215 """Returns a fully-qualified folder string."""
216 return "folders/{folder}".format(
217 folder=folder,
218 )
219
220 @staticmethod
221 def parse_common_folder_path(path: str) -> Dict[str, str]:
222 """Parse a folder path into its component segments."""
223 m = re.match(r"^folders/(?P<folder>.+?)$", path)
224 return m.groupdict() if m else {}
225
226 @staticmethod
227 def common_organization_path(
228 organization: str,
229 ) -> str:
230 """Returns a fully-qualified organization string."""
231 return "organizations/{organization}".format(
232 organization=organization,
233 )
234
235 @staticmethod
236 def parse_common_organization_path(path: str) -> Dict[str, str]:
237 """Parse a organization path into its component segments."""
238 m = re.match(r"^organizations/(?P<organization>.+?)$", path)
239 return m.groupdict() if m else {}
240
241 @staticmethod
242 def common_project_path(
243 project: str,
244 ) -> str:
245 """Returns a fully-qualified project string."""
246 return "projects/{project}".format(
247 project=project,
248 )
249
250 @staticmethod
251 def parse_common_project_path(path: str) -> Dict[str, str]:
252 """Parse a project path into its component segments."""
253 m = re.match(r"^projects/(?P<project>.+?)$", path)
254 return m.groupdict() if m else {}
255
256 @staticmethod
257 def common_location_path(
258 project: str,
259 location: str,
260 ) -> str:
261 """Returns a fully-qualified location string."""
262 return "projects/{project}/locations/{location}".format(
263 project=project,
264 location=location,
265 )
266
267 @staticmethod
268 def parse_common_location_path(path: str) -> Dict[str, str]:
269 """Parse a location path into its component segments."""
270 m = re.match(r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$", path)
271 return m.groupdict() if m else {}
272
273 @classmethod
274 def get_mtls_endpoint_and_cert_source(
275 cls, client_options: Optional[client_options_lib.ClientOptions] = None
276 ):
277 """Return the API endpoint and client cert source for mutual TLS.
278
279 The client cert source is determined in the following order:
280 (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
281 client cert source is None.
282 (2) if `client_options.client_cert_source` is provided, use the provided one; if the
283 default client cert source exists, use the default one; otherwise the client cert
284 source is None.
285
286 The API endpoint is determined in the following order:
287 (1) if `client_options.api_endpoint` if provided, use the provided one.
288 (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
289 default mTLS endpoint; if the environment variable is "never", use the default API
290 endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
291 use the default API endpoint.
292
293 More details can be found at https://google.aip.dev/auth/4114.
294
295 Args:
296 client_options (google.api_core.client_options.ClientOptions): Custom options for the
297 client. Only the `api_endpoint` and `client_cert_source` properties may be used
298 in this method.
299
300 Returns:
301 Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
302 client cert source to use.
303
304 Raises:
305 google.auth.exceptions.MutualTLSChannelError: If any errors happen.
306 """
307 if client_options is None:
308 client_options = client_options_lib.ClientOptions()
309 use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")
310 use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
311 if use_client_cert not in ("true", "false"):
312 raise ValueError(
313 "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
314 )
315 if use_mtls_endpoint not in ("auto", "never", "always"):
316 raise MutualTLSChannelError(
317 "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
318 )
319
320 # Figure out the client cert source to use.
321 client_cert_source = None
322 if use_client_cert == "true":
323 if client_options.client_cert_source:
324 client_cert_source = client_options.client_cert_source
325 elif mtls.has_default_client_cert_source():
326 client_cert_source = mtls.default_client_cert_source()
327
328 # Figure out which api endpoint to use.
329 if client_options.api_endpoint is not None:
330 api_endpoint = client_options.api_endpoint
331 elif use_mtls_endpoint == "always" or (
332 use_mtls_endpoint == "auto" and client_cert_source
333 ):
334 api_endpoint = cls.DEFAULT_MTLS_ENDPOINT
335 else:
336 api_endpoint = cls.DEFAULT_ENDPOINT
337
338 return api_endpoint, client_cert_source
339
340 def __init__(
341 self,
342 *,
343 credentials: Optional[ga_credentials.Credentials] = None,
344 transport: Optional[Union[str, ErrorGroupServiceTransport]] = None,
345 client_options: Optional[Union[client_options_lib.ClientOptions, dict]] = None,
346 client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
347 ) -> None:
348 """Instantiates the error group service client.
349
350 Args:
351 credentials (Optional[google.auth.credentials.Credentials]): The
352 authorization credentials to attach to requests. These
353 credentials identify the application to the service; if none
354 are specified, the client will attempt to ascertain the
355 credentials from the environment.
356 transport (Union[str, ErrorGroupServiceTransport]): The
357 transport to use. If set to None, a transport is chosen
358 automatically.
359 client_options (Optional[Union[google.api_core.client_options.ClientOptions, dict]]): Custom options for the
360 client. It won't take effect if a ``transport`` instance is provided.
361 (1) The ``api_endpoint`` property can be used to override the
362 default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT
363 environment variable can also be used to override the endpoint:
364 "always" (always use the default mTLS endpoint), "never" (always
365 use the default regular endpoint) and "auto" (auto switch to the
366 default mTLS endpoint if client certificate is present, this is
367 the default value). However, the ``api_endpoint`` property takes
368 precedence if provided.
369 (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable
370 is "true", then the ``client_cert_source`` property can be used
371 to provide client certificate for mutual TLS transport. If
372 not provided, the default SSL client certificate will be used if
373 present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not
374 set, no client certificate will be used.
375 client_info (google.api_core.gapic_v1.client_info.ClientInfo):
376 The client info used to send a user-agent string along with
377 API requests. If ``None``, then default info will be used.
378 Generally, you only need to set this if you're developing
379 your own client library.
380
381 Raises:
382 google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport
383 creation failed for any reason.
384 """
385 if isinstance(client_options, dict):
386 client_options = client_options_lib.from_dict(client_options)
387 if client_options is None:
388 client_options = client_options_lib.ClientOptions()
389 client_options = cast(client_options_lib.ClientOptions, client_options)
390
391 api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source(
392 client_options
393 )
394
395 api_key_value = getattr(client_options, "api_key", None)
396 if api_key_value and credentials:
397 raise ValueError(
398 "client_options.api_key and credentials are mutually exclusive"
399 )
400
401 # Save or instantiate the transport.
402 # Ordinarily, we provide the transport, but allowing a custom transport
403 # instance provides an extensibility point for unusual situations.
404 if isinstance(transport, ErrorGroupServiceTransport):
405 # transport is a ErrorGroupServiceTransport instance.
406 if credentials or client_options.credentials_file or api_key_value:
407 raise ValueError(
408 "When providing a transport instance, "
409 "provide its credentials directly."
410 )
411 if client_options.scopes:
412 raise ValueError(
413 "When providing a transport instance, provide its scopes "
414 "directly."
415 )
416 self._transport = transport
417 else:
418 import google.auth._default # type: ignore
419
420 if api_key_value and hasattr(
421 google.auth._default, "get_api_key_credentials"
422 ):
423 credentials = google.auth._default.get_api_key_credentials(
424 api_key_value
425 )
426
427 Transport = type(self).get_transport_class(transport)
428 self._transport = Transport(
429 credentials=credentials,
430 credentials_file=client_options.credentials_file,
431 host=api_endpoint,
432 scopes=client_options.scopes,
433 client_cert_source_for_mtls=client_cert_source_func,
434 quota_project_id=client_options.quota_project_id,
435 client_info=client_info,
436 always_use_jwt_access=True,
437 api_audience=client_options.api_audience,
438 )
439
440 def get_group(
441 self,
442 request: Optional[Union[error_group_service.GetGroupRequest, dict]] = None,
443 *,
444 group_name: Optional[str] = None,
445 retry: OptionalRetry = gapic_v1.method.DEFAULT,
446 timeout: Union[float, object] = gapic_v1.method.DEFAULT,
447 metadata: Sequence[Tuple[str, str]] = (),
448 ) -> common.ErrorGroup:
449 r"""Get the specified group.
450
451 .. code-block:: python
452
453 # This snippet has been automatically generated and should be regarded as a
454 # code template only.
455 # It will require modifications to work:
456 # - It may require correct/in-range values for request initialization.
457 # - It may require specifying regional endpoints when creating the service
458 # client as shown in:
459 # https://googleapis.dev/python/google-api-core/latest/client_options.html
460 from google.cloud import errorreporting_v1beta1
461
462 def sample_get_group():
463 # Create a client
464 client = errorreporting_v1beta1.ErrorGroupServiceClient()
465
466 # Initialize request argument(s)
467 request = errorreporting_v1beta1.GetGroupRequest(
468 group_name="group_name_value",
469 )
470
471 # Make the request
472 response = client.get_group(request=request)
473
474 # Handle the response
475 print(response)
476
477 Args:
478 request (Union[google.cloud.errorreporting_v1beta1.types.GetGroupRequest, dict]):
479 The request object. A request to return an individual
480 group.
481 group_name (str):
482 Required. The group resource name. Written as
483 ``projects/{projectID}/groups/{group_name}``. Call
484 ```groupStats.list`` <https://cloud.google.com/error-reporting/reference/rest/v1beta1/projects.groupStats/list>`__
485 to return a list of groups belonging to this project.
486
487 Example: ``projects/my-project-123/groups/my-group``
488
489 This corresponds to the ``group_name`` field
490 on the ``request`` instance; if ``request`` is provided, this
491 should not be set.
492 retry (google.api_core.retry.Retry): Designation of what errors, if any,
493 should be retried.
494 timeout (float): The timeout for this request.
495 metadata (Sequence[Tuple[str, str]]): Strings which should be
496 sent along with the request as metadata.
497
498 Returns:
499 google.cloud.errorreporting_v1beta1.types.ErrorGroup:
500 Description of a group of similar
501 error events.
502
503 """
504 # Create or coerce a protobuf request object.
505 # Quick check: If we got a request object, we should *not* have
506 # gotten any keyword arguments that map to the request.
507 has_flattened_params = any([group_name])
508 if request is not None and has_flattened_params:
509 raise ValueError(
510 "If the `request` argument is set, then none of "
511 "the individual field arguments should be set."
512 )
513
514 # Minor optimization to avoid making a copy if the user passes
515 # in a error_group_service.GetGroupRequest.
516 # There's no risk of modifying the input as we've already verified
517 # there are no flattened fields.
518 if not isinstance(request, error_group_service.GetGroupRequest):
519 request = error_group_service.GetGroupRequest(request)
520 # If we have keyword arguments corresponding to fields on the
521 # request, apply these.
522 if group_name is not None:
523 request.group_name = group_name
524
525 # Wrap the RPC method; this adds retry and timeout information,
526 # and friendly error handling.
527 rpc = self._transport._wrapped_methods[self._transport.get_group]
528
529 # Certain fields should be provided within the metadata header;
530 # add these here.
531 metadata = tuple(metadata) + (
532 gapic_v1.routing_header.to_grpc_metadata(
533 (("group_name", request.group_name),)
534 ),
535 )
536
537 # Send the request.
538 response = rpc(
539 request,
540 retry=retry,
541 timeout=timeout,
542 metadata=metadata,
543 )
544
545 # Done; return the response.
546 return response
547
548 def update_group(
549 self,
550 request: Optional[Union[error_group_service.UpdateGroupRequest, dict]] = None,
551 *,
552 group: Optional[common.ErrorGroup] = None,
553 retry: OptionalRetry = gapic_v1.method.DEFAULT,
554 timeout: Union[float, object] = gapic_v1.method.DEFAULT,
555 metadata: Sequence[Tuple[str, str]] = (),
556 ) -> common.ErrorGroup:
557 r"""Replace the data for the specified group.
558 Fails if the group does not exist.
559
560 .. code-block:: python
561
562 # This snippet has been automatically generated and should be regarded as a
563 # code template only.
564 # It will require modifications to work:
565 # - It may require correct/in-range values for request initialization.
566 # - It may require specifying regional endpoints when creating the service
567 # client as shown in:
568 # https://googleapis.dev/python/google-api-core/latest/client_options.html
569 from google.cloud import errorreporting_v1beta1
570
571 def sample_update_group():
572 # Create a client
573 client = errorreporting_v1beta1.ErrorGroupServiceClient()
574
575 # Initialize request argument(s)
576 request = errorreporting_v1beta1.UpdateGroupRequest(
577 )
578
579 # Make the request
580 response = client.update_group(request=request)
581
582 # Handle the response
583 print(response)
584
585 Args:
586 request (Union[google.cloud.errorreporting_v1beta1.types.UpdateGroupRequest, dict]):
587 The request object. A request to replace the existing
588 data for the given group.
589 group (google.cloud.errorreporting_v1beta1.types.ErrorGroup):
590 Required. The group which replaces
591 the resource on the server.
592
593 This corresponds to the ``group`` field
594 on the ``request`` instance; if ``request`` is provided, this
595 should not be set.
596 retry (google.api_core.retry.Retry): Designation of what errors, if any,
597 should be retried.
598 timeout (float): The timeout for this request.
599 metadata (Sequence[Tuple[str, str]]): Strings which should be
600 sent along with the request as metadata.
601
602 Returns:
603 google.cloud.errorreporting_v1beta1.types.ErrorGroup:
604 Description of a group of similar
605 error events.
606
607 """
608 # Create or coerce a protobuf request object.
609 # Quick check: If we got a request object, we should *not* have
610 # gotten any keyword arguments that map to the request.
611 has_flattened_params = any([group])
612 if request is not None and has_flattened_params:
613 raise ValueError(
614 "If the `request` argument is set, then none of "
615 "the individual field arguments should be set."
616 )
617
618 # Minor optimization to avoid making a copy if the user passes
619 # in a error_group_service.UpdateGroupRequest.
620 # There's no risk of modifying the input as we've already verified
621 # there are no flattened fields.
622 if not isinstance(request, error_group_service.UpdateGroupRequest):
623 request = error_group_service.UpdateGroupRequest(request)
624 # If we have keyword arguments corresponding to fields on the
625 # request, apply these.
626 if group is not None:
627 request.group = group
628
629 # Wrap the RPC method; this adds retry and timeout information,
630 # and friendly error handling.
631 rpc = self._transport._wrapped_methods[self._transport.update_group]
632
633 # Certain fields should be provided within the metadata header;
634 # add these here.
635 metadata = tuple(metadata) + (
636 gapic_v1.routing_header.to_grpc_metadata(
637 (("group.name", request.group.name),)
638 ),
639 )
640
641 # Send the request.
642 response = rpc(
643 request,
644 retry=retry,
645 timeout=timeout,
646 metadata=metadata,
647 )
648
649 # Done; return the response.
650 return response
651
652 def __enter__(self) -> "ErrorGroupServiceClient":
653 return self
654
655 def __exit__(self, type, value, traceback):
656 """Releases underlying transport's resources.
657
658 .. warning::
659 ONLY use as a context manager if the transport is NOT shared
660 with other clients! Exiting the with block will CLOSE the transport
661 and may cause errors in other clients!
662 """
663 self.transport.close()
664
665
666DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
667 gapic_version=package_version.__version__
668)
669
670
671__all__ = ("ErrorGroupServiceClient",)