Skip to content
This repository has been archived by the owner on Sep 12, 2024. It is now read-only.

feat(connectors): add SAP HANA connector #961

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion chaos_genius/connectors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from chaos_genius.connectors.snowflake import SnowflakeDb
from chaos_genius.connectors.redshift import Redshift
from chaos_genius.connectors.druid import Druid

from chaos_genius.connectors.hana import Hana

DB_CLASS_MAPPER = {
"Postgres": PostgresDb,
Expand All @@ -13,6 +13,7 @@
"Snowflake": SnowflakeDb,
"Redshift": Redshift,
"Druid": Druid,
"Hana": Hana,
}


Expand Down
88 changes: 88 additions & 0 deletions chaos_genius/connectors/hana.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""SAP HANA DB connector."""

import pandas as pd
from sqlalchemy import create_engine, text

from chaos_genius.connectors.base_db import BaseDb

from .connector_utils import merge_dataframe_chunks


class Hana(BaseDb):
"""SAP HANA DB connector."""

test_db_query = "SELECT * FROM SYS.DUMMY LIMIT 1"

def get_db_uri(self):
"""Create SQLAlchemy URI from data source info."""
db_info = self.ds_info
if db_info is None:
raise Exception("Datasource info not found for SAP HANA.")

host = db_info.get("host")
port = int(db_info.get("port"))
username = db_info.get("username")
database = db_info.get("database", "")
password = db_info.get("password")
if not (host and port):
raise Exception("Database Credential not found for SAP HANA.")

if not (username and password):
self.sqlalchemy_db_uri = f"hana+hdbcli://{host}:{port}/{database}"
else:
self.sqlalchemy_db_uri = (
f"hana+hdbcli://{username}:{password}@{host}:{port}/{database}"
)
return self.sqlalchemy_db_uri

def get_db_engine(self):
"""Create an SQLAlchemy engine from data source info."""
db_uri = self.get_db_uri()
self.engine = create_engine(
db_uri,
echo=self.debug,
)
return self.engine

def test_connection(self):
"""Test data source connection."""
if not hasattr(self, "engine") or not self.engine:
self.engine = self.get_db_engine()
query_text = text(self.test_db_query)
status, message = None, ""
try:
with self.engine.connect() as connection:
cursor = connection.execute(query_text)
results = cursor.all()
# HANA has a dummy table with "X" as the single value
if results[0][0] == "X":
status = True
else:
status = False
except Exception as err_msg: # noqa: B902
status = False
message = str(err_msg)
return status, message

def run_query(self, query, as_df=True):
"""Run a SQL query."""
engine = self.get_db_engine()
if as_df:
return merge_dataframe_chunks(
pd.read_sql_query(query, engine, chunksize=self.CHUNKSIZE)
)
else:
return []

def get_schema(self):
"""Get schema name."""
schema_name = self.ds_info.get("schema") if self.ds_info is not None else None
if schema_name:
self.schema = schema_name
else:
self.schema = "public"
return self.schema

def get_schema_names_list(self):
data = self.inspector.get_schema_names()
return data
783 changes: 782 additions & 1 deletion chaos_genius/third_party/data_connection_config.json

Large diffs are not rendered by default.

11 changes: 10 additions & 1 deletion chaos_genius/third_party/integration_server_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"e2d65910-8c8b-40a1-ae7d-ee2416b2bfa2": False, # Snowflake
"e87ffa8e-a3b5-f69c-9076-6011339de1f6": False, # Redshift
"5B45DB62-303C-4E70-92DA-419D3CDBD506": False, # Druid
"9f698366-2575-4ec3-bfb6-ff28313c38c9": False, # SAP HANA
# "29b409d9-30a5-4cc8-ad50-886eb846fea3", # Quickbooks
}

Expand Down Expand Up @@ -116,7 +117,15 @@
"username": "username",
"password": "password",
"db_type": "druid"
}
},
"9f698366-2575-4ec3-bfb6-ff28313c38c9": {
"host": "host",
"port": "port",
"username": "username",
"database": "database",
"passowrd": "password",
"db_type": "hana",
},
}

SOURCE_ICON_OVERRIDE = {
Expand Down
14 changes: 11 additions & 3 deletions chaos_genius/utils/metadata_api_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"Redshift": True,
"BigQuery": False,
"Snowflake": True,
"Druid": False
"Druid": False,
"Hana": True,
}

TABLE_VIEW_MATERIALIZED_VIEW_AVAILABILITY = {
Expand Down Expand Up @@ -49,7 +50,14 @@
"materialized_views": True,
"supported_aggregations": ["sum", "count"],
"supports_multidim_dd": False
}
},
"Hana": {
"tables": True,
"views": True,
"materialized_views": True,
"supported_aggregations": ["mean", "sum", "count"],
"supports_multidim_dd": True
},
}

TABLE_VIEW_MATERIALIZED_VIEW_AVAILABILITY_THIRD_PARTY = {
Expand All @@ -66,4 +74,4 @@
if conf["supports_multidim_dd"]
]

NON_THIRD_PARTY_DATASOURCES = TABLE_VIEW_MATERIALIZED_VIEW_AVAILABILITY.keys()
NON_THIRD_PARTY_DATASOURCES = TABLE_VIEW_MATERIALIZED_VIEW_AVAILABILITY.keys()
3 changes: 3 additions & 0 deletions requirements/prod.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ snowflake-sqlalchemy==1.2.4
sqlalchemy-redshift==0.8.6
# For apache druid
pydruid[sqlalchemy]~=0.6.2
# For SAP HANA
sqlalchemy-hana~=0.5.0
hdbcli~=2.12.25

# Migrations
Flask-Migrate==2.7.0
Expand Down