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

V1.7.1 #100

Merged
merged 5 commits into from
Nov 29, 2023
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/publish-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ jobs:
uses: actions/checkout@v4

- name: Log in to the Container registry
uses: docker/login-action@v2.2.0
uses: docker/login-action@v3.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push Docker image
uses: docker/build-push-action@v4.2.1
uses: docker/build-push-action@v5.1.0
with:
context: devops
build-args: PYTHON_VERSION=${{ matrix.python_version }}
Expand Down
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,39 @@
# Changelog

### v1.7.1

## Features

* Added capability support structure in fabric adapter
* Added metadata freshness checks
* Updated catalog fetch performance improvements to handle relations with many pre-existing objects
* Added dbt-show support to 1.7.1

## Enhancements

* improve connection manager logging
* Added metadata freshness checks tests
* Added capability support tests
* Added catalog fetch performance improvements
* Added dbt show's --limit flag tests
* Added storing test failures tests

### v1.6.1

## Features

* Fabric DW now supports sp_rename. Starting v1.6.1 sp_rename is metadata operation
* Enabled table clone feature

## Enhancements

* Addressed [Issue 53](https://github.com/microsoft/dbt-fabric/issues/53)
* Added explicit support for [Issue 76 - ActiveDirectoryServicePrincipal authentication](https://github.com/microsoft/dbt-fabric/issues/74)
* Removed port number support in connection string as it is no longer required in Microsoft Fabric DW
* Removed MSI authentication as it does not make sense for Microsoft Fabric.
* Table lock hints are not supported by Fabric DW
* Supported authentication modes are ActiveDirectory* and AZ CLI

### v1.7.0

## Features
Expand Down
2 changes: 1 addition & 1 deletion dbt/adapters/fabric/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version = "1.7.0"
version = "1.7.1"
7 changes: 7 additions & 0 deletions dbt/adapters/fabric/fabric_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from dbt.adapters.base.meta import available
from dbt.adapters.base.relation import BaseRelation
from dbt.adapters.cache import _make_ref_key_dict
from dbt.adapters.capability import Capability, CapabilityDict, CapabilitySupport, Support

# from dbt.adapters.cache import _make_ref_key_msg
from dbt.adapters.sql import SQLAdapter
Expand All @@ -27,6 +28,12 @@ class FabricAdapter(SQLAdapter):
Column = FabricColumn
AdapterSpecificConfigs = FabricConfigs

_capabilities: CapabilityDict = CapabilityDict(
{
Capability.SchemaMetadataByRelations: CapabilitySupport(support=Support.Full),
Capability.TableLastModifiedMetadata: CapabilitySupport(support=Support.Full),
}
)
CONSTRAINT_SUPPORT = {
ConstraintType.check: ConstraintSupport.NOT_SUPPORTED,
ConstraintType.not_null: ConstraintSupport.ENFORCED,
Expand Down
88 changes: 32 additions & 56 deletions dbt/adapters/fabric/fabric_connection_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,15 @@
import dbt.exceptions
import pyodbc
from azure.core.credentials import AccessToken
from azure.identity import (
AzureCliCredential,
ClientSecretCredential,
DefaultAzureCredential,
EnvironmentCredential,
ManagedIdentityCredential,
)
from azure.identity import AzureCliCredential, DefaultAzureCredential, EnvironmentCredential
from dbt.adapters.sql import SQLConnectionManager
from dbt.clients.agate_helper import empty_table
from dbt.contracts.connection import AdapterResponse, Connection, ConnectionState
from dbt.events import AdapterLogger
from dbt.events.contextvars import get_node_info
from dbt.events.functions import fire_event
from dbt.events.types import ConnectionUsed, SQLQuery, SQLQueryStatus
from dbt.utils import cast_to_str

from dbt.adapters.fabric import __version__
from dbt.adapters.fabric.fabric_credentials import FabricCredentials
Expand Down Expand Up @@ -113,24 +111,6 @@ def get_cli_access_token(credentials: FabricCredentials) -> AccessToken:
return token


def get_msi_access_token(credentials: FabricCredentials) -> AccessToken:
"""
Get an Azure access token from the system's managed identity

Parameters
-----------
credentials: FabricCredentials
Credentials.

Returns
-------
out : AccessToken
The access token.
"""
token = ManagedIdentityCredential().get_token(AZURE_CREDENTIAL_SCOPE)
return token


def get_auto_access_token(credentials: FabricCredentials) -> AccessToken:
"""
Get an Azure access token automatically through azure-identity
Expand Down Expand Up @@ -167,30 +147,8 @@ def get_environment_access_token(credentials: FabricCredentials) -> AccessToken:
return token


def get_sp_access_token(credentials: FabricCredentials) -> AccessToken:
"""
Get an Azure access token using the SP credentials.

Parameters
----------
credentials : FabricCredentials
Credentials.

Returns
-------
out : AccessToken
The access token.
"""
token = ClientSecretCredential(
str(credentials.tenant_id), str(credentials.client_id), str(credentials.client_secret)
).get_token(AZURE_CREDENTIAL_SCOPE)
return token


AZURE_AUTH_FUNCTIONS: Mapping[str, AZURE_AUTH_FUNCTION_TYPE] = {
"serviceprincipal": get_sp_access_token,
"cli": get_cli_access_token,
"msi": get_msi_access_token,
"auto": get_auto_access_token,
"environment": get_environment_access_token,
}
Expand Down Expand Up @@ -335,7 +293,7 @@ def open(cls, connection: Connection) -> Connection:
# SQL Server named instance. In this case then port number has to be omitted.
con_str.append(f"SERVER={credentials.host}")
else:
con_str.append(f"SERVER={credentials.host},{credentials.port}")
con_str.append(f"SERVER={credentials.host}")

con_str.append(f"Database={credentials.database}")

Expand All @@ -347,14 +305,16 @@ def open(cls, connection: Connection) -> Connection:
if credentials.authentication == "ActiveDirectoryPassword":
con_str.append(f"UID={{{credentials.UID}}}")
con_str.append(f"PWD={{{credentials.PWD}}}")
if credentials.authentication == "ActiveDirectoryServicePrincipal":
con_str.append(f"UID={{{credentials.client_id}}}")
con_str.append(f"PWD={{{credentials.client_secret}}}")
elif credentials.authentication == "ActiveDirectoryInteractive":
con_str.append(f"UID={{{credentials.UID}}}")

elif credentials.windows_login:
con_str.append("trusted_connection=Yes")
elif credentials.authentication == "sql":
con_str.append(f"UID={{{credentials.UID}}}")
con_str.append(f"PWD={{{credentials.PWD}}}")
raise pyodbc.DatabaseError("SQL Authentication is not supported by Microsoft Fabric")

# https://docs.microsoft.com/en-us/sql/relational-databases/native-client/features/using-encryption-without-validation?view=sql-server-ver15
assert credentials.encrypt is not None
Expand Down Expand Up @@ -435,13 +395,26 @@ def add_query(
if auto_begin and connection.transaction_open is False:
self.begin()

logger.debug('Using {} connection "{}".'.format(self.TYPE, connection.name))
fire_event(
ConnectionUsed(
conn_type=self.TYPE,
conn_name=cast_to_str(connection.name),
node_info=get_node_info(),
)
)

with self.exception_handler(sql):
if abridge_sql_log:
logger.debug("On {}: {}....".format(connection.name, sql[0:512]))
log_sql = "{}...".format(sql[:512])
else:
logger.debug("On {}: {}".format(connection.name, sql))
log_sql = sql

fire_event(
SQLQuery(
conn_name=cast_to_str(connection.name), sql=log_sql, node_info=get_node_info()
)
)

pre = time.time()

cursor = connection.handle.cursor()
Expand All @@ -460,9 +433,11 @@ def add_query(
# https://github.com/mkleehammer/pyodbc/issues/134#issuecomment-281739794
connection.handle.add_output_converter(-155, byte_array_to_datetime)

logger.debug(
"SQL status: {} in {:0.2f} seconds".format(
self.get_response(cursor), (time.time() - pre)
fire_event(
SQLQueryStatus(
status=str(self.get_response(cursor)),
elapsed=round((time.time() - pre)),
node_info=get_node_info(),
)
)

Expand Down Expand Up @@ -498,6 +473,7 @@ def data_type_code_to_name(cls, type_code: Union[str, str]) -> str:
def execute(
self, sql: str, auto_begin: bool = True, fetch: bool = False, limit: Optional[int] = None
) -> Tuple[AdapterResponse, agate.Table]:
sql = self._add_query_comment(sql)
_, cursor = self.add_query(sql, auto_begin)
response = self.get_response(cursor)
if fetch:
Expand Down
7 changes: 4 additions & 3 deletions dbt/adapters/fabric/fabric_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ class FabricCredentials(Credentials):
host: str
database: str
schema: str
port: Optional[int] = 1433
UID: Optional[str] = None
PWD: Optional[str] = None
windows_login: Optional[bool] = False
tenant_id: Optional[str] = None
client_id: Optional[str] = None
client_secret: Optional[str] = None
authentication: Optional[str] = "sql"
authentication: Optional[str] = "ActiveDirectoryServicePrincipal"
encrypt: Optional[bool] = True # default value in MS ODBC Driver 18 as well
trust_cert: Optional[bool] = False # default value in MS ODBC Driver 18 as well
retries: int = 1
Expand Down Expand Up @@ -49,11 +48,13 @@ def _connection_keys(self):
if self.windows_login is True:
self.authentication = "Windows Login"

if self.authentication.lower().strip() == "serviceprincipal":
self.authentication = "ActiveDirectoryServicePrincipal"

return (
"server",
"database",
"schema",
"port",
"UID",
"client_id",
"authentication",
Expand Down
Loading
Loading