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

Commit

Permalink
feat(connectors): add SAP HANA connector
Browse files Browse the repository at this point in the history
Closes #960

TODO:
- Consider renaming the connector to `HANA` or `SAP HANA` since `Hana`
  isn't correct (it's an abbreviation).
  • Loading branch information
Samyak2 committed May 23, 2022
1 parent 33fdf1c commit 386e837
Show file tree
Hide file tree
Showing 6 changed files with 896 additions and 6 deletions.
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

0 comments on commit 386e837

Please sign in to comment.