Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GCS]-Parse configurations from Kibana UI #493

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
d2aab73
parse configs from ui by formating the private-key
jignesh-crest Feb 16, 2023
bcc60b1
Add custom exception, remove unwanted shilds
jignesh-crest Feb 17, 2023
18b97e6
Merge branch 'main' into handle-configuration-from-ui
jignesh-crest Feb 20, 2023
47d0418
Merge branch 'main' of github.com:jignesh-crest/connectors-python int…
jignesh-crest Mar 2, 2023
1238165
use validate config from basesource
jignesh-crest Mar 2, 2023
fa2acc6
don't save the parsed json
jignesh-crest Mar 2, 2023
228a698
Merge branch 'main' into handle-configuration-from-ui
jignesh-crest Mar 10, 2023
598d2e6
Merge branch 'main' of github.com:jignesh-crest/connectors-python int…
jignesh-crest Mar 15, 2023
45c804c
move get_pem_format to utils, rename and make initialize as getter me…
jignesh-crest Mar 15, 2023
7f3df56
Merge branch 'main' of github.com:jignesh-crest/connectors-python int…
jignesh-crest Mar 16, 2023
ca65deb
implement client class for abstracting api calls
jignesh-crest Mar 16, 2023
fb25b6e
Use the getter instead of relying on the initialization of the storag…
jignesh-crest Mar 16, 2023
d59fa1f
add tests for the get_client and use getter for google client
jignesh-crest Mar 17, 2023
5dffd46
update test
jignesh-crest Mar 17, 2023
4c7e88b
Merge branch 'main' into handle-configuration-from-ui
jignesh-crest Mar 20, 2023
ea031ba
Expose api_call method as public method, reame method
jignesh-crest Mar 20, 2023
31c74f1
Merge branch 'main' into handle-configuration-from-ui
jignesh-crest Mar 21, 2023
4a0b747
cached property for google client, make it private
jignesh-crest Mar 21, 2023
0f1ad0e
Merge branch 'main' into handle-configuration-from-ui
jignesh-crest Mar 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions connectors/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@
"""


class DataSourceConfigurationError(Exception):
"""Raise when configurations are invalid.

Args:
Exception (DataSourceConfigurationError): Invalid configurations exception.
jignesh-crest marked this conversation as resolved.
Show resolved Hide resolved
"""

pass


class Field:
def __init__(self, name, label=None, value="", type="str"):
if label is None:
Expand Down
83 changes: 62 additions & 21 deletions connectors/sources/google_cloud_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import os
import urllib.parse
from functools import partial
from json.decoder import JSONDecodeError

import aiofiles
from aiofiles.os import remove
Expand All @@ -18,7 +19,7 @@
from aiogoogle.auth.creds import ServiceAccountCreds

from connectors.logger import logger
from connectors.source import BaseDataSource
from connectors.source import BaseDataSource, DataSourceConfigurationError
from connectors.utils import TIKA_SUPPORTED_FILETYPES, convert_to_b64

CLOUD_STORAGE_READ_ONLY_SCOPE = "https://www.googleapis.com/auth/devstorage.read_only"
Expand Down Expand Up @@ -72,27 +73,14 @@ def __init__(self, configuration):
configuration (DataSourceConfiguration): Object of DataSourceConfiguration class.
"""
super().__init__(configuration=configuration)
if not self.configuration["service_account_credentials"]:
raise Exception("service_account_credentials can't be empty.")

self.credentials = (
self.configuration["service_account_credentials"]
.strip()
.encode("unicode_escape")
.decode()
)
self.service_account_credentials = ServiceAccountCreds(
scopes=[CLOUD_STORAGE_READ_ONLY_SCOPE],
**json.loads(
self.configuration["service_account_credentials"]
if RUNNING_FTEST
else self.credentials
),
)
self.user_project_id = self.service_account_credentials.project_id

self.retry_count = self.configuration["retry_count"]
self.enable_content_extraction = self.configuration["enable_content_extraction"]

self.service_account_credentials = None
self.user_project_id = None
self.json_creds = None

@classmethod
def get_default_configuration(cls):
"""Get the default configuration for Google Cloud Storage.
Expand All @@ -113,7 +101,7 @@ def get_default_configuration(cls):
return {
"service_account_credentials": {
"value": json.dumps(default_credentials),
"label": "JSON string for Google Cloud service account",
"label": "Google Cloud service account json",
"type": "str",
},
"retry_count": {
Expand Down Expand Up @@ -199,8 +187,61 @@ async def _api_call(
)
await asyncio.sleep(DEFAULT_WAIT_MULTIPLIER**retry_counter)

def _validate_configurations(self):
"""Validates whether user inputs are valid or not for configuration field.

Raises:
DataSourceConfigurationError: The service account json is empty.
DataSourceConfigurationError: The service account json is in invalid format.
"""
if self.configuration["service_account_credentials"] == "":
jignesh-crest marked this conversation as resolved.
Show resolved Hide resolved
raise DataSourceConfigurationError("Service account json can't be empty.")
try:
self.json_creds = json.loads(
self.configuration["service_account_credentials"]
)
except JSONDecodeError:
raise DataSourceConfigurationError(
"Service account json is not in valid format."
)

def get_pem_format(self, private_key, max_split=-1):
jignesh-crest marked this conversation as resolved.
Show resolved Hide resolved
"""Convert key into PEM format.

Args:
private_key (str): Private_key in raw format.
max_split (int): Specifies how many splits to do. Defaults to -1.

Returns:
string: PEM format
"""
private_key = private_key.replace(" ", "\n")
private_key = " ".join(private_key.split("\n", max_split))
private_key = " ".join(private_key.rsplit("\n", max_split))
return private_key

def _initialize_configurations(self):
"""Initialize the ServiceAccountCreds"""
if (
self.json_creds.get("private_key")
and "\n" not in self.json_creds["private_key"]
):
self.json_creds["private_key"] = self.get_pem_format(
private_key=self.json_creds["private_key"].strip(), max_split=2
)

self.service_account_credentials = ServiceAccountCreds(
scopes=[CLOUD_STORAGE_READ_ONLY_SCOPE],
**self.json_creds,
)
self.user_project_id = self.service_account_credentials.project_id

async def ping(self):
"""Verify the connection with Google Cloud Storage"""
"""Verify the configurations and connection with Google Cloud Storage"""

self._validate_configurations()
self._initialize_configurations()

if RUNNING_FTEST:
jignesh-crest marked this conversation as resolved.
Show resolved Hide resolved
return
try:
Expand Down
46 changes: 44 additions & 2 deletions connectors/sources/tests/test_google_cloud_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ def get_mocked_source_object():
{"service_account_credentials": SERVICE_ACCOUNT_CREDENTIALS, "retry_count": 0}
)
mocked_gcs_object = GoogleCloudStorageDataSource(configuration=configuration)
mocked_gcs_object._validate_configurations()
mocked_gcs_object._initialize_configurations()
return mocked_gcs_object


Expand Down Expand Up @@ -62,10 +64,25 @@ async def test_empty_configuration():

# Setup
configuration = DataSourceConfiguration({"service_account_credentials": ""})
gcs_object = GoogleCloudStorageDataSource(configuration=configuration)

# Execute
with pytest.raises(Exception, match="service_account_credentials can't be empty."):
_ = GoogleCloudStorageDataSource(configuration=configuration)
with pytest.raises(Exception, match="Service account json can't be empty."):
gcs_object._validate_configurations()


def test_invalid_configuration():
"""Tests that the service account credential is in invalid json format"""

# Setup
configuration = DataSourceConfiguration(
{"service_account_credentials": "{'abc':'bcd','cd'}"}
)
gcs_object = GoogleCloudStorageDataSource(configuration=configuration)

# Execute
with pytest.raises(Exception, match="Service account json is not in valid format."):
gcs_object._validate_configurations()


@pytest.mark.asyncio
Expand Down Expand Up @@ -499,3 +516,28 @@ async def test_api_call_for_attribute_error(catch_stdout, patch_logger):
userProject=mocked_gcs_object.user_project_id,
):
print("Method called successfully....")


def test_get_pem_format():
"""This function tests prepare private key with dummy values"""
# Setup
expected_formated_pem_key = """-----BEGIN PRIVATE KEY-----
PrivateKey
-----END PRIVATE KEY-----"""
source = get_mocked_source_object()
private_key = "-----BEGIN PRIVATE KEY----- PrivateKey -----END PRIVATE KEY-----"

# Execute
formated_privat_key = source.get_pem_format(private_key, max_split=2)
assert formated_privat_key == expected_formated_pem_key

# Setup
expected_formated_certificate = """-----BEGIN CERTIFICATE-----
Certificate1
Certificate2
-----END CERTIFICATE-----"""
private_key = "-----BEGIN CERTIFICATE----- Certificate1 Certificate2 -----END CERTIFICATE-----"

# Execute
formated_privat_key = source.get_pem_format(private_key, max_split=1)
assert formated_privat_key == expected_formated_certificate