Skip to content

Commit

Permalink
Add external access templates for snowpark and streamlit
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-turbaszek committed Oct 8, 2024
1 parent d60db9e commit cabcf3a
Show file tree
Hide file tree
Showing 17 changed files with 315 additions and 0 deletions.
4 changes: 4 additions & 0 deletions snowpark_with_external_access/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.packages/
.venv/
app.zip
__pycache__
49 changes: 49 additions & 0 deletions snowpark_with_external_access/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Snowpark project using external access

This is a simple example of a Snowpark project that requires external access.

## Prerequisites
This project requires a database, API integration and secret. To created them you can execute convenience script
`snow sql -f setup.sql` or run the following SQL commands:

```sql
CREATE DATABASE IF NOT EXISTS <! database_name | to_snowflake_identifier !>;
CREATE SCHEMA IF NOT EXISTS <! database_name | to_snowflake_identifier !>.<! schema_name | to_snowflake_identifier !>;
USE SCHEMA <! database_name | to_snowflake_identifier !>.<! schema_name | to_snowflake_identifier !>;
CREATE SECRET IF NOT EXISTS <! secret_name | to_snowflake_identifier !> TYPE = GENERIC_STRING SECRET_STRING = 'very_secret_string';
CREATE OR REPLACE NETWORK RULE snowpark_example_network_rule
MODE = EGRESS
TYPE = HOST_PORT
VALUE_LIST = ('docs.snowflake.com');

CREATE EXTERNAL ACCESS INTEGRATION IF NOT EXISTS <! external_access_integration_name !>
ALLOWED_NETWORK_RULES = (snowpark_example_network_rule)
ALLOWED_AUTHENTICATION_SECRETS = (<! secret_name | to_snowflake_identifier !>)
ENABLED = true;
```

## Building Snowpark artifacts
_For more information see [build documentation](https://docs.snowflake.com/developer-guide/snowflake-cli/snowpark/build)._

First you need to bundle your code by running:
```bash
snow snowpark build
```

## Deploying the project
_For more information see [deploy documentation](https://docs.snowflake.com/developer-guide/snowflake-cli/snowpark/deploy)._

To deploy the snowpark application:

```bash
snow snowpark deploy
```

## Testing the project

You can test the deployed snowpark application by running:

```bash
snow snowpark execute function "<! database_name | to_snowflake_identifier !>.<! schema_name | to_snowflake_identifier !>.request_function()";
snow snowpark execute procedure "<! database_name | to_snowflake_identifier !>.<! schema_name | to_snowflake_identifier !>.request_procedure()";
```
Empty file.
14 changes: 14 additions & 0 deletions snowpark_with_external_access/app/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import _snowflake
from http.client import HTTPSConnection


def get_secret_value():
return _snowflake.get_generic_secret_string("generic_secret")


def send_request():
host = "docs.snowflake.com"
conn = HTTPSConnection(host)
conn.request("GET", "/")
response = conn.getresponse()
return response.status
9 changes: 9 additions & 0 deletions snowpark_with_external_access/app/functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from common import get_secret_value, send_request


def request_function() -> str:
# Retrieve secret value
_ = get_secret_value()

# Send request
return send_request()
12 changes: 12 additions & 0 deletions snowpark_with_external_access/app/procedures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from __future__ import annotations

from snowflake.snowpark import Session
from common import get_secret_value, send_request


def request_procedure(session: Session) -> str:
# Retrieve secret value
_ = get_secret_value()

# Send request
return send_request()
1 change: 1 addition & 0 deletions snowpark_with_external_access/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
snowflake-snowpark-python
15 changes: 15 additions & 0 deletions snowpark_with_external_access/setup.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CREATE DATABASE IF NOT EXISTS <! database_name | to_snowflake_identifier !>;
CREATE SCHEMA IF NOT EXISTS <! database_name | to_snowflake_identifier !>.<! schema_name | to_snowflake_identifier !>;
USE SCHEMA <! database_name | to_snowflake_identifier !>.<! schema_name | to_snowflake_identifier !>;

CREATE SECRET IF NOT EXISTS <! secret_name | to_snowflake_identifier !> TYPE = GENERIC_STRING SECRET_STRING = 'very_secret_string';

CREATE OR REPLACE NETWORK RULE snowpark_example_network_rule
MODE = EGRESS
TYPE = HOST_PORT
VALUE_LIST = ('docs.snowflake.com');

CREATE EXTERNAL ACCESS INTEGRATION IF NOT EXISTS <! external_access_integration_name !>
ALLOWED_NETWORK_RULES = (snowpark_example_network_rule)
ALLOWED_AUTHENTICATION_SECRETS = (<! secret_name | to_snowflake_identifier !>)
ENABLED = true;
52 changes: 52 additions & 0 deletions snowpark_with_external_access/snowflake.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# For more information about structure of snowflake.yml for Snowpark see
# https://docs.snowflake.com/en/developer-guide/snowflake-cli/snowpark/create
definition_version: '2'
entities:
request_function:
type: function
# Uses context variables to create fully qualified name of the function
identifier:
name: request_function
schema: <% ctx.env.schema %>
database: <% ctx.env.database %>
handler: functions.request_function
returns: string
# No arguments for this function
signature: ""
meta:
use_mixins:
- external_access
- snowpark_shared

request_procedure:
type: procedure
# Uses context variables to create fully qualified name of the procedure
identifier:
name: request_procedure
schema: <% ctx.env.schema %>
database: <% ctx.env.database %>
handler: procedures.request_procedure
returns: string
# No arguments for this procedure
signature: ""
meta:
use_mixins:
- external_access
- snowpark_shared

mixins:
# This mixin defines shared configuration for external access
external_access:
secrets:
# generic_secret is key used by the get_secret_value method to reference the secret
generic_secret: <! secret_name | to_snowflake_identifier !>
external_access_integrations:
- <! external_access_integration_name !>
snowpark_shared:
artifacts:
- app/
stage: <% ctx.env.database %>.<% ctx.env.schema %>.<! stage_name | to_snowflake_identifier !>

env:
schema: <! schema_name | to_snowflake_identifier !>
database: <! database_name | to_snowflake_identifier !>
24 changes: 24 additions & 0 deletions snowpark_with_external_access/template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
files_to_render:
- snowflake.yml
- README.md
- setup.sql
variables:
- name: database_name
prompt: "Database where the functions and procedures will be created"
type: string
- name: schema_name
prompt: "Schema where the functions and procedures will be created"
type: string
default: public
- name: stage_name
prompt: "What stage should the functions and procedures be deployed to"
default: dev_deployment
type: string
- name: secret_name
prompt: "Secret name to be used in the functions and procedures"
type: string
default: snowpark_secret
- name: external_access_integration_name
prompt: "External access integration name to be used in the functions and procedures"
type: string
default: snowpark_external_access_integration
4 changes: 4 additions & 0 deletions streamlit_with_external_access/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.packages/
.venv/
app.zip
__pycache__
34 changes: 34 additions & 0 deletions streamlit_with_external_access/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Streamlit application with external access

This is a simple example of a Streamlit application that requires external access.

## Prerequisites
This project requires a database, API integration and secret. To created them you can execute convenience script
`snow sql -f setup.sql` or run the following SQL commands:

```sql
CREATE DATABASE IF NOT EXISTS <! database_name | to_snowflake_identifier !>;
CREATE SCHEMA IF NOT EXISTS <! database_name | to_snowflake_identifier !>.<! schema_name | to_snowflake_identifier !>;
USE SCHEMA <! database_name | to_snowflake_identifier !>.<! schema_name | to_snowflake_identifier !>;

CREATE SECRET IF NOT EXISTS <! secret_name | to_snowflake_identifier !> TYPE = GENERIC_STRING SECRET_STRING = 'very_secret_string';

CREATE OR REPLACE NETWORK RULE streamlit_example_network_rule
MODE = EGRESS
TYPE = HOST_PORT
VALUE_LIST = ('docs.snowflake.com');

CREATE EXTERNAL ACCESS INTEGRATION IF NOT EXISTS <! external_access_integration_name !>
ALLOWED_NETWORK_RULES = (streamlit_example_network_rule)
ALLOWED_AUTHENTICATION_SECRETS = (<! secret_name | to_snowflake_identifier !>)
ENABLED = true;
```

## Deploying the streamlit application
_For more information see [deploy documentation](https://docs.snowflake.com/developer-guide/snowflake-cli/streamlit-apps/manage-apps/deploy-app)._

To deploy the Streamlit application, you should run:

```bash
snow streamlit deploy
```
1 change: 1 addition & 0 deletions streamlit_with_external_access/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
snowflake-snowpark-python
15 changes: 15 additions & 0 deletions streamlit_with_external_access/setup.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CREATE DATABASE IF NOT EXISTS <! database_name | to_snowflake_identifier !>;
CREATE SCHEMA IF NOT EXISTS <! database_name | to_snowflake_identifier !>.<! schema_name | to_snowflake_identifier !>;
USE SCHEMA <! database_name | to_snowflake_identifier !>.<! schema_name | to_snowflake_identifier !>;

CREATE SECRET IF NOT EXISTS <! secret_name | to_snowflake_identifier !> TYPE = GENERIC_STRING SECRET_STRING = 'very_secret_string';

CREATE OR REPLACE NETWORK RULE streamlit_example_network_rule
MODE = EGRESS
TYPE = HOST_PORT
VALUE_LIST = ('docs.snowflake.com');

CREATE EXTERNAL ACCESS INTEGRATION IF NOT EXISTS <! external_access_integration_name !>
ALLOWED_NETWORK_RULES = (streamlit_example_network_rule)
ALLOWED_AUTHENTICATION_SECRETS = (<! secret_name | to_snowflake_identifier !>)
ENABLED = true;
35 changes: 35 additions & 0 deletions streamlit_with_external_access/snowflake.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# For more information about structure of snowflake.yml for Streamlit see
# https://docs.snowflake.com/developer-guide/snowflake-cli/streamlit-apps/manage-apps/initialize-app#create-the-project-definition-for-a-streamlit-app
definition_version: '2'
entities:
dashboard:
type: 'streamlit'
# Uses context variables to create fully qualified name of the dashboard
identifier:
name: 'dashboard'
schema: <% ctx.env.schema %>
database: <% ctx.env.database %>
query_warehouse: <! warehouse_name !>
artifacts:
- streamlit_app.py
meta:
use_mixins:
- external_access
- deployment_stage

mixins:
# This mixin defines shared configuration for external access
external_access:
secrets:
# generic_secret is key used by get_secret_value method to reference the secret
generic_secret: <! secret_name | to_snowflake_identifier !>
external_access_integrations:
- <! external_access_integration_name !>

deployment_stage:
# Uses context variables to create fully qualified name of stage
stage: <% ctx.env.database %>.<% ctx.env.schema %>.<! stage_name | to_snowflake_identifier !>

env:
schema: <! schema_name | to_snowflake_identifier !>
database: <! database_name | to_snowflake_identifier !>
19 changes: 19 additions & 0 deletions streamlit_with_external_access/streamlit_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import _snowflake
import streamlit as st
from http.client import HTTPSConnection


def get_secret_value():
return _snowflake.get_generic_secret_string("generic_secret")


def send_request():
host = "docs.snowflake.com"
conn = HTTPSConnection(host)
conn.request("GET", "/")
response = conn.getresponse()
st.success(f"Response status: {response.status}")


st.title(f"Example streamlit app.")
st.button("Send request", on_click=send_request)
27 changes: 27 additions & 0 deletions streamlit_with_external_access/template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
files_to_render:
- snowflake.yml
- README.md
- setup.sql
variables:
- name: database_name
prompt: "Database where the application will be created"
type: string
- name: schema_name
prompt: "Schema where the application will be created"
type: string
default: public
- name: warehouse_name
prompt: "Warehouse to be used by the application"
type: string
- name: stage_name
prompt: "What stage should the procedures and functions be deployed to"
default: dev_deployment
type: string
- name: secret_name
prompt: "Secret name to be used in the procedures and functions"
type: string
default: streamlit_secret
- name: external_access_integration_name
prompt: "External access integration name to be used in the procedures and functions"
type: string
default: streamlit_external_access_integration

0 comments on commit cabcf3a

Please sign in to comment.