Skip to content
This repository was archived by the owner on May 20, 2022. It is now read-only.

Commit 3a8357c

Browse files
authored
Merge pull request #4 from fyndata/develop
Release 0.1.0
2 parents eaa45ce + 236027b commit 3a8357c

19 files changed

+1352
-9
lines changed

fd_gcp/__init__.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""
2+
Fyndata's library of Google Cloud Platform (GCP) utils
3+
======================================================
4+
5+
Among other things, this library makes it easier to interact with some
6+
GCP services or even mock the interaction with them.
7+
8+
Each module that is dedicated to interact with an specific GCP service is named
9+
``gcp_{service_acronym}`` e.g. :mod:`gcp_kms`.
10+
11+
There are other modules for the external users of the library such as
12+
:mod:`exceptions` and :mod:`auth`.
13+
14+
15+
Google Resource Name (GRN)
16+
--------------------------
17+
18+
The terms *resource name* and *resource id* are used extensively in GCP's
19+
documentation and code. Because of the reasons below, for GCP we created an
20+
analogy of AWS' concept of *Amazon Resource Name* (ARN): *Google Resource Name*
21+
(GRN).
22+
23+
- Using the word "name" of X might be misleading since it seems too casual
24+
and one could easily say "the name of that key ring is ``my-keyring``" but
25+
that would be wrong: the format of the name of a key ring resource is
26+
``projects/[PROJECT_ID]/locations/[LOCATION_ID]/keyRings/[KEY_RING_ID]``.
27+
- It is annoying to have code entities named such as
28+
``kms_crypto_key_resource_name`` (unlike ``kms_crypto_key_id``).
29+
30+
"""

fd_gcp/_http.py

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import logging
2+
3+
import google.auth.exceptions
4+
import googleapiclient.errors
5+
import googleapiclient.http
6+
import httplib2
7+
8+
from . import exceptions
9+
10+
11+
logger = logging.getLogger(__name__)
12+
13+
14+
def execute_google_api_client_request(
15+
request: googleapiclient.http.HttpRequest,
16+
) -> httplib2.Response:
17+
try:
18+
response = request.execute()
19+
except google.auth.exceptions.GoogleAuthError as exc:
20+
raise exceptions.AuthError from exc
21+
except googleapiclient.errors.HttpError as exc:
22+
new_exc = exceptions.process_googleapiclient_http_error(exc)
23+
raise new_exc from exc
24+
except googleapiclient.errors.Error as exc:
25+
raise exceptions.UnrecognizedApiError from exc
26+
27+
return response

fd_gcp/auth.py

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"""
2+
Authentication and authorization utilities.
3+
4+
"""
5+
import logging
6+
7+
import google.auth.compute_engine
8+
import google.auth.credentials
9+
import google.auth.exceptions
10+
11+
from . import exceptions
12+
from .common import GcpCredentials
13+
14+
# Make sure package 'cryptography' is available for 'google.auth', which prefers that lib instead
15+
# of falling back (silently) to package 'rsa' (pure Python).
16+
# https://github.com/googleapis/google-auth-library-python/blob/v1.5.1/google/auth/crypt/rsa.py#L19
17+
try:
18+
import google.auth.crypt._cryptography_rsa
19+
except ImportError as exc: # pragma: no cover
20+
msg = "Package 'cryptography' is required for optimum performance of 'google.auth'."
21+
raise ImportError(msg) from exc
22+
23+
24+
logger = logging.getLogger(__name__)
25+
26+
27+
def get_env_default_credentials() -> GcpCredentials:
28+
"""
29+
Return the default credentials for the current GCP environment.
30+
31+
.. warning:: if the env var ``GOOGLE_APPLICATION_CREDENTIALS`` is set, then
32+
the returned value might correspond to something else.
33+
34+
"""
35+
try:
36+
credentials, _ = google.auth.default()
37+
except google.auth.exceptions.DefaultCredentialsError as exc:
38+
raise exceptions.AuthError from exc
39+
return credentials
40+
41+
42+
def get_env_project_id() -> str:
43+
"""
44+
Return the project ID of the current GCP environment.
45+
46+
.. warning:: if the env var ``GOOGLE_APPLICATION_CREDENTIALS`` is set, then
47+
the returned value might correspond to something else.
48+
49+
"""
50+
try:
51+
_, project_id = google.auth.default()
52+
except google.auth.exceptions.DefaultCredentialsError as exc:
53+
raise exceptions.AuthError from exc
54+
if not isinstance(project_id, str):
55+
raise exceptions.Error("Unexpected Google Auth lib response.", project_id)
56+
57+
return project_id
58+
59+
60+
def get_gce_credentials(service_account_email: str =None) -> GcpCredentials:
61+
"""
62+
Return credentials provided by Compute Engine service account.
63+
64+
.. warning:: This function does not attempt to authenticate or verify that
65+
the ``service_account_email`` does indeed exist. It will return a
66+
credentials object anyway.
67+
68+
A Compute Engine instance may have multiple service accounts.
69+
70+
`Google's Auth Library for Python docs`_ say:
71+
72+
"Applications running on Compute Engine, Container Engine, or the
73+
App Engine flexible environment can obtain credentials provided by
74+
Compute Engine service accounts."
75+
76+
.. _Google's Auth Library for Python docs:
77+
https://google-auth.readthedocs.io/en/latest/user-guide.html#compute-engine-container-engine-and-the-app-engine-flexible-environment
78+
79+
"""
80+
service_account_email = service_account_email or 'default'
81+
return google.auth.compute_engine.Credentials(service_account_email)
82+
83+
84+
def load_credentials_from_file(filename: str) -> GcpCredentials:
85+
credentials, _ = google.auth._default._load_credentials_from_file(filename)
86+
return credentials

fd_gcp/common.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""
2+
Definitions and data useful for many services modules.
3+
4+
"""
5+
# warning: do NOT remove any of these definitions, even though they are not used in this module.
6+
from google.auth.credentials import Credentials as GcpCredentials # noqa: F401
7+
from googleapiclient.discovery import Resource as GcpResource # noqa: F401

fd_gcp/constants.py

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""
2+
GCP's or this library's-specific common constants.
3+
4+
"""
5+
6+
# GCP project ID
7+
# > A project ID must start with a lowercase letter, and can contain only ASCII letters, digits,
8+
# > and hyphens, and must be between 6 and 30 characters.
9+
# https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project
10+
PROJECT_ID_MAX_LENGTH = 30
11+
# TODO: PROJECT_ID_REGEX = re.compile(r'^...$')
12+
13+
# GCP region ID
14+
# https://cloud.google.com/about/locations/
15+
# note: as of 2018-10-22, we have not found anywhere official the value of this restriction.
16+
# note: as of 2018-10-22, the longest region ID is 'northamerica-northeast1' (23 characters).
17+
REGION_ID_MAX_LENGTH_ESTIMATION = 48
18+
# TODO: REGION_ID_MAX_LENGTH

0 commit comments

Comments
 (0)