Skip to content

Commit 05f4bd8

Browse files
committed
Add GCS storage support for EA
Change-Id: I553016e1b78518b017737b37b3df47f60b85a138 Reviewed-on: https://review.couchbase.org/c/TAF/+/241861 Reviewed-by: Ritesh Agarwal <ritesh.agarwal@couchbase.com> Tested-by: Himanshu Jain <himanshu.jain@couchbase.com>
1 parent c578080 commit 05f4bd8

4 files changed

Lines changed: 111 additions & 26 deletions

File tree

couchbase_utils/cb_server_rest_util/analytics/analytics_settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,6 @@ def update_analytics_settings(
8787
params["blobStorageListEventuallyConsistent"] = "true"
8888
if blob_storage_force_path_style:
8989
params["blobStoragePathStyleAddressing"] = "true"
90+
self.log.info(f"Updating analytics settings with params: {params}")
9091
status, content, _ = self.request(api, self.POST, params=params)
9192
return status, content

pytests/Columnar/external_links_datasets_GCS.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@
55
"""
66
import random
77
from queue import Queue
8+
from TestInput import TestInputSingleton
89

9-
from Columnar.columnar_base import ColumnarBaseTest
10+
runtype = TestInputSingleton.input.param("runtype", "default").lower()
11+
if runtype == "columnar":
12+
from Columnar.columnar_base import ColumnarBaseTest
13+
else:
14+
from Columnar.onprem.columnar_onprem_base import ColumnarOnPremBase as ColumnarBaseTest
1015

1116

1217
class GCSLinksDatasets(ColumnarBaseTest):
@@ -19,7 +24,10 @@ def setUp(self):
1924
super(GCSLinksDatasets, self).setUp()
2025

2126
# Since all the test cases are being run on 1 cluster only
22-
self.columnar_cluster = self.tenant.columnar_instances[0]
27+
if runtype == "columnar":
28+
self.columnar_cluster = self.tenant.columnar_instances[0]
29+
else:
30+
self.columnar_cluster = self.cluster
2331

2432
if not self.columnar_spec_name:
2533
self.columnar_spec_name = "full_template"

pytests/Columnar/onprem/columnar_onprem_base.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from couchbase_utils.cbas_utils.cbas_utils_columnar import CbasUtil as columnarCBASUtil
88
from Jython_tasks.java_loader_tasks import SiriusCouchbaseLoader
99

10+
import os
11+
import json
1012

1113
class ColumnarOnPremBase(CBASBaseTest):
1214

@@ -169,6 +171,20 @@ def populate_columnar_infra_spec(
169171
"accountKey": self.aws_secret_key,
170172
"endpoint": self.aws_endpoint
171173
}]
174+
elif self.input.param("external_link_source", "s3") == "gcs":
175+
try:
176+
# gcs_certificate variable should be set in jenkins to use here
177+
self.log.info("Fetching certificate file path from the env: gcp_access_file")
178+
gcs_certificate = os.getenv('gcp_access_file')
179+
with open(gcs_certificate, 'r') as file:
180+
# Load JSON data from file
181+
data = json.load(file)
182+
columnar_spec["external_link"]["properties"] = [{
183+
"type": "gcs",
184+
"jsonCredentials": data
185+
}]
186+
except Exception as err:
187+
raise err
172188
else:
173189
columnar_spec["external_link"]["properties"] = [{
174190
"type": "s3",

pytests/onPrem_basetestcase.py

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from docker_utils.DockerSDK import DockerClient
3535
from awsLib.S3 import S3
3636
from azureLib.Azure import Azure
37+
from gcs import GCS
3738

3839

3940
class OnPremBaseTest(CouchbaseBaseTest):
@@ -79,9 +80,6 @@ def setUp(self):
7980
self.collection_factor = self.input.param("collection_factor", 0.1)
8081
self.collection_scale = self.input.param("collection_scale", None)
8182

82-
# Azure Blob params
83-
self.az_blob = self.input.param("az_blob", False)
84-
8583
# CBAS setting
8684
self.jre_path = self.input.param("jre_path", None)
8785
self.enable_dp = self.input.param("enable_dp", False)
@@ -460,6 +458,21 @@ def setUp(self):
460458
self.aws_session_token = None
461459
self.aws_endpoint = self.input.param("aws_endpoint", "https://testeaazureblob.blob.core.windows.net")
462460
self.aws_region = self.input.param("aws_region", "us-east-1")
461+
462+
elif self.storage_provider == "gs":
463+
self.log.info("Fetching certificate file path from the env: gcp_access_file")
464+
self.gcs_certificate = os.getenv('gcp_access_file')
465+
self.aws_region = "us-east1"
466+
with open(self.gcs_certificate, 'r') as file:
467+
# Load JSON data from file
468+
self.gcs_credentials_data = json.load(file)
469+
470+
for server in self.servers:
471+
if server.type == "analytics":
472+
if not self._configure_gs_credentials_on_host(
473+
server, self.gcs_credentials_data):
474+
self.log.error("Failed to configure AWS credentials on EA Analytics node")
475+
463476
# End: Analytics (EA) parameters
464477

465478
self.nebula = self.input.param("nebula", False)
@@ -702,7 +715,7 @@ def initialize_cluster(self, cluster_name, cluster, services=None,
702715
self.columnar_aws_secret_key = self.input.param("columnar_aws_secret_key",
703716
self.aws_secret_key)
704717

705-
if self.az_blob and not self.columnar_aws_secret_key.endswith("=="):
718+
if self.storage_provider == "azure" and not self.columnar_aws_secret_key.endswith("=="):
706719
self.columnar_aws_secret_key = self.columnar_aws_secret_key + "=="
707720
self.aws_secret_key = self.aws_secret_key + "=="
708721
self.columnar_aws_region = self.input.param("columnar_aws_region",
@@ -721,7 +734,36 @@ def initialize_cluster(self, cluster_name, cluster, services=None,
721734
session_token=self.columnar_aws_session_token,
722735
region=self.columnar_aws_region,
723736
endpoint_url=self.columnar_aws_endpoint)
724-
if not self.az_blob:
737+
self.columnar_azure_bucket_created = False
738+
self.columnar_gs_bucket_created = False
739+
740+
if self.storage_provider == "azure":
741+
self.azure_client = Azure(
742+
account_name=self.columnar_aws_access_key,
743+
account_key=self.columnar_aws_secret_key)
744+
self.log.info("Account Name {0}".format(self.columnar_aws_access_key))
745+
self.log.info("Account key {0}".format(self.columnar_aws_secret_key))
746+
self.columnar_azure_bucket_name = "columnar-build-sanity-" + str(int(
747+
time.time()))
748+
749+
if self.azure_client.create_container(self.columnar_azure_bucket_name):
750+
self.columnar_azure_bucket_created = True
751+
self.columnar_aws_bucket_name = self.columnar_azure_bucket_name
752+
else:
753+
self.fail("Creating Azure container - {0}. Failed.".format(
754+
self.columnar_azure_bucket_name))
755+
elif self.storage_provider == "gs":
756+
self.columnar_gs_bucket_name = "columnar-build-sanity-" + str(int(
757+
time.time()))
758+
self.gcs_client = GCS(self.gcs_credentials_data)
759+
self.log.info("Creating GCS bucket {}".format(self.columnar_gs_bucket_name))
760+
if self.gcs_client.create_bucket(self.columnar_gs_bucket_name):
761+
self.columnar_gs_bucket_created = True
762+
self.columnar_aws_bucket_name = self.columnar_gs_bucket_name
763+
else:
764+
self.fail("Creating GCS bucket - {0}. Failed.".format(
765+
self.columnar_gs_bucket_name))
766+
else:
725767
for i in range(5):
726768
try:
727769
self.columnar_aws_bucket_name = "columnar-build-sanity-" + str(int(
@@ -738,23 +780,8 @@ def initialize_cluster(self, cluster_name, cluster, services=None,
738780
self.log.error(str(e))
739781
if not self.columnar_aws_bucket_created:
740782
self.fail("Unable to create S3 bucket.")
741-
else:
742-
self.azure_client = Azure(
743-
account_name=self.columnar_aws_access_key,
744-
account_key=self.columnar_aws_secret_key)
745-
self.log.info("Account Name {0}".format(self.columnar_aws_access_key))
746-
self.log.info("Account key {0}".format(self.columnar_aws_secret_key))
747-
self.columnar_azure_bucket_name = "columnar-build-sanity-" + str(int(
748-
time.time()))
749-
750-
if self.azure_client.create_container(self.columnar_azure_bucket_name):
751-
self.columnar_azure_bucket_created = True
752-
self.columnar_aws_bucket_name = self.columnar_azure_bucket_name
753-
else:
754-
self.fail("Creating Azure container - {0}. Failed.".format(
755-
self.columnar_azure_bucket_name))
756783

757-
self.log.info("Adding aws bucket credentials to analytics")
784+
self.log.info("Setup compute storage separation for analytics")
758785
status = self.configure_compute_storage_separation_for_analytics(
759786
server=cluster.master, aws_access_key=self.columnar_aws_access_key,
760787
aws_secret_key=self.columnar_aws_secret_key,
@@ -1020,6 +1047,12 @@ def tearDownEverything(self, reset_cluster_env_vars=True):
10201047
self.columnar_azure_bucket_name))
10211048
if not self.azure_client.delete_container(self.columnar_azure_bucket_name):
10221049
self.log.error("Azure container {} failed to delete.".format(self.columnar_azure_bucket_name))
1050+
elif self.analytics_compute_storage_separation and getattr(self, "columnar_gs_bucket_created", False):
1051+
self.log.info("Deleting GCS bucket - {}".format(
1052+
self.columnar_gs_bucket_name))
1053+
if not self.gcs_client.delete_bucket(self.columnar_gs_bucket_name):
1054+
self.log.error("GCS bucket {} failed to delete.".format(
1055+
self.columnar_gs_bucket_name))
10231056

10241057
# Deleting all backups from test runs in the backup location
10251058
for server in self.servers:
@@ -1579,6 +1612,31 @@ def handle_setup_exception(self, exception_obj):
15791612
self.set_ports_for_server(server, "non_ssl")
15801613
super(OnPremBaseTest, self).handle_setup_exception(exception_obj)
15811614

1615+
def _configure_gs_credentials_on_host(self, server, gcs_credentials):
1616+
"""
1617+
Create /home/couchbase/.config/gcloud/application_default_credentials.json
1618+
with the given GCP credentials.
1619+
"""
1620+
gcp_dir = "/home/couchbase/.config/gcloud"
1621+
creds_path = gcp_dir + "/application_default_credentials.json"
1622+
1623+
creds_content = json.dumps(gcs_credentials) + "\n"
1624+
creds_b64 = base64.b64encode(creds_content.encode("utf-8")).decode("ascii")
1625+
1626+
shell = RemoteMachineShellConnection(server)
1627+
try:
1628+
shell.execute_command("mkdir -p {}".format(gcp_dir))
1629+
shell.execute_command("echo '{}' | base64 -d > {}".format(creds_b64, creds_path))
1630+
shell.execute_command("chown -R couchbase:couchbase /home/couchbase/.config")
1631+
shell.execute_command("chmod 600 {}".format(creds_path))
1632+
self.log.info("Configured GCP credentials at {} on {}".format(creds_path, server.ip))
1633+
return True
1634+
except Exception as e:
1635+
self.log.error("Failed to configure GCP credentials on host: {}".format(e))
1636+
return False
1637+
finally:
1638+
shell.disconnect()
1639+
15821640
def _remove_aws_credentials_from_host(self, server):
15831641
"""
15841642
Remove /home/couchbase/.aws directory to clean up any AWS credentials
@@ -1662,7 +1720,8 @@ def configure_compute_storage_separation_for_analytics(
16621720
"""
16631721
rest = AnalyticsRestAPI(server)
16641722

1665-
if self.storage_provider != "aws":
1723+
# Netapp, OCI, Azure
1724+
if self.storage_provider in ["netapp", "oci", "azure"]:
16661725
self.log.info(f"Setting aws access key id: {aws_access_key}")
16671726
status, content = rest.set_blob_storage_access_key_id(
16681727
access_key_id=aws_access_key)
@@ -1677,9 +1736,10 @@ def configure_compute_storage_separation_for_analytics(
16771736
self.log.error(f"Failed to set aws secret access key: {status} {str(content)}")
16781737
return False
16791738

1680-
self.log.info("Adding aws bucket config to analytics")
1681-
if self.az_blob:
1739+
if self.storage_provider == "azure":
16821740
blob_storage_scheme = "azblob"
1741+
elif self.storage_provider == "gs":
1742+
blob_storage_scheme = "gs"
16831743
else:
16841744
blob_storage_scheme = "s3"
16851745
status, content = rest.update_analytics_settings(

0 commit comments

Comments
 (0)