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

docs: snowflake mssql example #8736

Merged
merged 1 commit into from
Jan 13, 2025
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
31 changes: 31 additions & 0 deletions cleanup.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
-- Switch to ACCOUNTADMIN role for full cleanup permissions
USE ROLE ACCOUNTADMIN;

-- Try to use database if it exists
BEGIN
USE DATABASE MSSQL_API_DB;
USE SCHEMA MSSQL_API_SCHEMA;

-- Drop objects that need database context first
DROP PROCEDURE IF EXISTS OCKAM_MSSQL_QUERY();
DROP PROCEDURE IF EXISTS OCKAM_MSSQL_EXECUTE();
DROP FUNCTION IF EXISTS _OCKAM_QUERY_MSSQL(STRING);
DROP FUNCTION IF EXISTS _OCKAM_MSSQL_EXECUTE(STRING);
DROP FUNCTION IF EXISTS OCKAM_MSSQL_INSERT(STRING, ARRAY);
DROP IMAGE REPOSITORY IF EXISTS MSSQL_API_REPOSITORY;
DROP SCHEMA IF EXISTS MSSQL_API_SCHEMA;
EXCEPTION
WHEN OTHER THEN
-- Database doesn't exist, continue with other cleanup
END;

-- Drop objects that don't need database context
DROP SERVICE IF EXISTS MSSQL_API_CLIENT;
DROP INTEGRATION IF EXISTS OCKAM;
DROP INTEGRATION IF EXISTS OCSP;
DROP NETWORK RULE IF EXISTS OCKAM_OUT;
DROP NETWORK RULE IF EXISTS OCSP_OUT;
DROP COMPUTE POOL IF EXISTS MSSQL_API_CP;
DROP WAREHOUSE IF EXISTS MSSQL_API_WH;
DROP DATABASE IF EXISTS MSSQL_API_DB;
DROP ROLE IF EXISTS MSSQL_API_ROLE;
203 changes: 203 additions & 0 deletions examples/command/portals/snowflake/example-7/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# Access Microsoft SQL Server from Snowpark Container Services

![Architecture](./diagram.png)

## Get started with Ockam

[Signup for Ockam](https://www.ockam.io/signup) and then run the following commands on your workstation:

```sh
# Install Ockam Command
curl --proto '=https' --tlsv1.2 -sSfL https://install.command.ockam.io | bash && source "$HOME/.ockam/env"

# Enroll with Ockam Orchestrator.
ockam enroll

# Create an enrollment ticket for the node that will run from a linux machine where thesql server is reachable from
ockam project ticket --usage-count 1 --expires-in 4h --attribute mssql --relay mssql > mssql_outlet.ticket

```

## Setup Ockam node next to MS SQL Server

- Copy `setup_ockam_outlet.sh` to the linux machine where the MS SQL Server is reachable from.
- Copy `mssql_outlet.ticket` to the same location as `setup_ockam_outlet.sh` script

```sh
# Run the setup script
chmod +x setup_ockam_outlet.sh
DB_ENDPOINT="HOST:1433" ./setup_ockam_outlet.sh
```

## Setup Snowflake

- Create the database, schema, role, compute pool, warehouse, and image repository.

```sh
# Run the init script
snowsql -f snowflake_scripts/init.sql
```

- Note the `Repository URL` value from the output to be used to build and publish consumer image to snowflake
- It will be similar to `XXX.registry.snowflakecomputing.com/mssql_api_db/mssql_api_schema/mssql_api_repository`

## Push Ockam docker image and MS SQL Server client docker image

```sh
cd mssql_client
# Use the Repository URL from the output of the init script

docker login <repository_url>

docker buildx build --platform linux/amd64 --load -t <repository_url>/mssql_client:latest .

docker push <repository_url>/mssql_client:latest

# Push Ockam
docker pull ghcr.io/build-trust/ockam:0.146.0@sha256:b13ed188dbde6f5cae9d2c9c9e9305f9c36a009b1e5c126ac0d066537510f895

docker tag ghcr.io/build-trust/ockam:0.146.0@sha256:b13ed188dbde6f5cae9d2c9c9e9305f9c36a009b1e5c126ac0d066537510f895 <repository_url>/ockam:latest

docker push <repository_url>/ockam:latest

cd -
```

## Create an Ockam node and API Client to connect to MS SQL Server in Snowpark Container Services

- Create network rules to allow the Ockam node to connect to your ockam project and for python client to connect to`ocsp.snowflakecomputing.com`

```bash
# Run from the same machine where you had enrolled to ockam project and created tickets
EGRESS_LIST=$(ockam project show --jq '.egress_allow_list[0]')
snowsql -f snowflake_scripts/access.sql --variable egress_list="$EGRESS_LIST"
```

- Create Service

```bash
# Replace below values with the values from MS SQL Server
OCKAM_TICKET=$(ockam project ticket --usage-count 1 --expires-in 1h --attribute snowflake)
MSSQL_DATABASE='TODO'
MSSQL_USER='TODO'
MSSQL_PASSWORD='TODO'

snowsql -f snowflake_scripts/service.sql \
--variable ockam_ticket="$OCKAM_TICKET" \
--variable mssql_database="$MSSQL_DATABASE" \
--variable mssql_user="$MSSQL_USER" \
--variable mssql_password="$MSSQL_PASSWORD"

```

- Ensure container services are running

```sql
-- Check service status
USE WAREHOUSE MSSQL_API_WH;
USE ROLE MSSQL_API_ROLE;
USE DATABASE MSSQL_API_DB;
USE SCHEMA MSSQL_API_SCHEMA;

SHOW SERVICES;
SELECT SYSTEM$GET_SERVICE_STATUS('MSSQL_API_CLIENT');

-- Check service logs
CALL SYSTEM$GET_SERVICE_LOGS('MSSQL_API_CLIENT', '0', 'http-endpoint', 100);
CALL SYSTEM$GET_SERVICE_LOGS('MSSQL_API_CLIENT', '0', 'ockam-inlet', 100);
```

> [!IMPORTANT]
> - `http-endpoint` is the endpoint that will be used to connect to the MS SQL Server. You will see `Successfully connected to SQL Server` in the logs upon successful connection.
> - `ockam-inlet` is the endpoint that will be used to connect to the Ockam node. Logs will indicate if there are any errors starting the node.

## Create Functions and Stored Procedures to use the API

```bash
# Run the functions script to create the stored procedures and functions
snowsql -f snowflake_scripts/functions.sql

```

## Access MS SQL Server from Snowflake

- Below are some examples of how to access MS SQL Server from Snowflake

__Execute a statement__

```sql

USE WAREHOUSE MSSQL_API_WH;
USE ROLE MSSQL_API_ROLE;
USE DATABASE MSSQL_API_DB;
USE SCHEMA MSSQL_API_SCHEMA;

CALL OCKAM_MSSQL_EXECUTE($$
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'PETS')
BEGIN
CREATE TABLE PETS (
NAME NVARCHAR(100),
BREED NVARCHAR(100)
);
END
$$);
```

__Insert data__

```sql
CALL OCKAM_MSSQL_EXECUTE($$
INSERT INTO PETS VALUES ('Toby', 'Beagle');
$$);
```

__Query the PostgreSQL database__

```sql
CALL OCKAM_MSSQL_QUERY('SELECT * FROM PETS');
```

__Join PostgreSQL and Snowflake tables__

```sql
-- Create two similar tables `PETS`, in MS SQL Server and Snowflake, but with different fields

-- MS SQL Server

CALL OCKAM_MSSQL_EXECUTE($$
IF OBJECT_ID('PETS', 'U') IS NOT NULL
DROP TABLE PETS;

IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'PETS')
BEGIN
CREATE TABLE PETS (
NAME NVARCHAR(100),
BREED NVARCHAR(100)
);
END;

INSERT INTO PETS VALUES ('Max', 'Golden Retriever');
INSERT INTO PETS VALUES ('Bella', 'Poodle');
$$);

-- Snowflake

CREATE TABLE IF NOT EXISTS PETS (NAME VARCHAR(100), YEAR_OF_BIRTH INT);
INSERT INTO PETS VALUES ('Max', 2018);
INSERT INTO PETS VALUES ('Bella', 2019);


-- First we query the remote MS SQL Server
CALL OCKAM_MSSQL_QUERY('SELECT * FROM PETS');
SET pets_query=LAST_QUERY_ID();

-- Join the results of the MS SQL Server query with the Snowflake table
SELECT * FROM TABLE(RESULT_SCAN($pets_query)) as MSSQL_PETS
INNER JOIN PETS ON MSSQL_PETS.NAME = PETS.NAME;
```

## Clean up

```bash
snowsql -f snowflake_scripts/cleanup.sql
```
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
ARG BASE_IMAGE=python:3.10-slim-buster
FROM $BASE_IMAGE

RUN pip install --upgrade pip && \
pip install flask snowflake snowflake-connector-python

RUN pip install pymssql==2.2.11

COPY service.py ./
COPY connection.py ./

CMD ["python3", "service.py"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import os
import logging
import snowflake.connector
from snowflake.snowpark import Session

def session() -> Session:
"""
Create a session for the connection
:return: Session
"""
logging.info(f"Create a session")
return Session.builder.configs({"connection": connection()}).create()


def connection() -> snowflake.connector.SnowflakeConnection:
"""
Create a connection, either from inside the native application when deployed
or with user/password credentials when testing locally

:return: A SnowflakeConnection
"""
logging.info(f"Create a connection")
if os.path.isfile("/snowflake/session/token"):
logging.info(f"Use an OAUTH token")
creds = {
"account": os.getenv("SNOWFLAKE_ACCOUNT"),
"host": os.getenv("SNOWFLAKE_HOST"),
"port": os.getenv("SNOWFLAKE_PORT"),
"protocol": "https",
"warehouse": os.getenv("SNOWFLAKE_WAREHOUSE"),
"database": os.getenv("SNOWFLAKE_DATABASE"),
"schema": os.getenv("SNOWFLAKE_SCHEMA"),
"role": os.getenv("SNOWFLAKE_ROLE"),
"authenticator": "oauth",
"token": open("/snowflake/session/token", "r").read(),
"client_session_keep_alive": True,
"ocsp_fail_open": False,
"validate_default_parameters": True,
}
logging.info(f"the creds are {creds}")
else:
creds = {
"account": os.getenv("SNOWFLAKE_ACCOUNT"),
"user": os.getenv("SNOWFLAKE_USER"),
"password": os.getenv("SNOWFLAKE_PASSWORD"),
"warehouse": os.getenv("SNOWFLAKE_WAREHOUSE"),
"database": os.getenv("SNOWFLAKE_DATABASE"),
"schema": os.getenv("SNOWFLAKE_SCHEMA"),
"client_session_keep_alive": True
}

return snowflake.connector.connect(**creds)
Loading
Loading