From cabcf3afc5d2a418fca89ddb4f9839f619bc8fb2 Mon Sep 17 00:00:00 2001 From: Tomasz Urbaszek Date: Tue, 8 Oct 2024 10:05:00 +0200 Subject: [PATCH] Add external access templates for snowpark and streamlit --- snowpark_with_external_access/.gitignore | 4 ++ snowpark_with_external_access/README.md | 49 +++++++++++++++++ snowpark_with_external_access/app/__init__.py | 0 snowpark_with_external_access/app/common.py | 14 +++++ .../app/functions.py | 9 ++++ .../app/procedures.py | 12 +++++ .../requirements.txt | 1 + snowpark_with_external_access/setup.sql | 15 ++++++ snowpark_with_external_access/snowflake.yml | 52 +++++++++++++++++++ snowpark_with_external_access/template.yml | 24 +++++++++ streamlit_with_external_access/.gitignore | 4 ++ streamlit_with_external_access/README.md | 34 ++++++++++++ .../requirements.txt | 1 + streamlit_with_external_access/setup.sql | 15 ++++++ streamlit_with_external_access/snowflake.yml | 35 +++++++++++++ .../streamlit_app.py | 19 +++++++ streamlit_with_external_access/template.yml | 27 ++++++++++ 17 files changed, 315 insertions(+) create mode 100644 snowpark_with_external_access/.gitignore create mode 100644 snowpark_with_external_access/README.md create mode 100644 snowpark_with_external_access/app/__init__.py create mode 100644 snowpark_with_external_access/app/common.py create mode 100644 snowpark_with_external_access/app/functions.py create mode 100644 snowpark_with_external_access/app/procedures.py create mode 100644 snowpark_with_external_access/requirements.txt create mode 100644 snowpark_with_external_access/setup.sql create mode 100644 snowpark_with_external_access/snowflake.yml create mode 100644 snowpark_with_external_access/template.yml create mode 100644 streamlit_with_external_access/.gitignore create mode 100644 streamlit_with_external_access/README.md create mode 100644 streamlit_with_external_access/requirements.txt create mode 100644 streamlit_with_external_access/setup.sql create mode 100644 streamlit_with_external_access/snowflake.yml create mode 100644 streamlit_with_external_access/streamlit_app.py create mode 100644 streamlit_with_external_access/template.yml diff --git a/snowpark_with_external_access/.gitignore b/snowpark_with_external_access/.gitignore new file mode 100644 index 0000000..55f74f6 --- /dev/null +++ b/snowpark_with_external_access/.gitignore @@ -0,0 +1,4 @@ +.packages/ +.venv/ +app.zip +__pycache__ diff --git a/snowpark_with_external_access/README.md b/snowpark_with_external_access/README.md new file mode 100644 index 0000000..6e18bdd --- /dev/null +++ b/snowpark_with_external_access/README.md @@ -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 ; +CREATE SCHEMA IF NOT EXISTS .; +USE SCHEMA .; +CREATE SECRET IF NOT EXISTS 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 + ALLOWED_NETWORK_RULES = (snowpark_example_network_rule) + ALLOWED_AUTHENTICATION_SECRETS = () + 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 "..request_function()"; +snow snowpark execute procedure "..request_procedure()"; +``` diff --git a/snowpark_with_external_access/app/__init__.py b/snowpark_with_external_access/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/snowpark_with_external_access/app/common.py b/snowpark_with_external_access/app/common.py new file mode 100644 index 0000000..ebcff8b --- /dev/null +++ b/snowpark_with_external_access/app/common.py @@ -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 diff --git a/snowpark_with_external_access/app/functions.py b/snowpark_with_external_access/app/functions.py new file mode 100644 index 0000000..f310364 --- /dev/null +++ b/snowpark_with_external_access/app/functions.py @@ -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() diff --git a/snowpark_with_external_access/app/procedures.py b/snowpark_with_external_access/app/procedures.py new file mode 100644 index 0000000..b90f067 --- /dev/null +++ b/snowpark_with_external_access/app/procedures.py @@ -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() diff --git a/snowpark_with_external_access/requirements.txt b/snowpark_with_external_access/requirements.txt new file mode 100644 index 0000000..ed706cf --- /dev/null +++ b/snowpark_with_external_access/requirements.txt @@ -0,0 +1 @@ +snowflake-snowpark-python diff --git a/snowpark_with_external_access/setup.sql b/snowpark_with_external_access/setup.sql new file mode 100644 index 0000000..2ac5126 --- /dev/null +++ b/snowpark_with_external_access/setup.sql @@ -0,0 +1,15 @@ +CREATE DATABASE IF NOT EXISTS ; +CREATE SCHEMA IF NOT EXISTS .; +USE SCHEMA .; + +CREATE SECRET IF NOT EXISTS 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 + ALLOWED_NETWORK_RULES = (snowpark_example_network_rule) + ALLOWED_AUTHENTICATION_SECRETS = () + ENABLED = true; diff --git a/snowpark_with_external_access/snowflake.yml b/snowpark_with_external_access/snowflake.yml new file mode 100644 index 0000000..92d76d8 --- /dev/null +++ b/snowpark_with_external_access/snowflake.yml @@ -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: + external_access_integrations: + - + snowpark_shared: + artifacts: + - app/ + stage: <% ctx.env.database %>.<% ctx.env.schema %>. + +env: + schema: + database: diff --git a/snowpark_with_external_access/template.yml b/snowpark_with_external_access/template.yml new file mode 100644 index 0000000..b23f73f --- /dev/null +++ b/snowpark_with_external_access/template.yml @@ -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 diff --git a/streamlit_with_external_access/.gitignore b/streamlit_with_external_access/.gitignore new file mode 100644 index 0000000..55f74f6 --- /dev/null +++ b/streamlit_with_external_access/.gitignore @@ -0,0 +1,4 @@ +.packages/ +.venv/ +app.zip +__pycache__ diff --git a/streamlit_with_external_access/README.md b/streamlit_with_external_access/README.md new file mode 100644 index 0000000..eb58057 --- /dev/null +++ b/streamlit_with_external_access/README.md @@ -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 ; +CREATE SCHEMA IF NOT EXISTS .; +USE SCHEMA .; + +CREATE SECRET IF NOT EXISTS 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 + ALLOWED_NETWORK_RULES = (streamlit_example_network_rule) + ALLOWED_AUTHENTICATION_SECRETS = () + 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 +``` diff --git a/streamlit_with_external_access/requirements.txt b/streamlit_with_external_access/requirements.txt new file mode 100644 index 0000000..ed706cf --- /dev/null +++ b/streamlit_with_external_access/requirements.txt @@ -0,0 +1 @@ +snowflake-snowpark-python diff --git a/streamlit_with_external_access/setup.sql b/streamlit_with_external_access/setup.sql new file mode 100644 index 0000000..ac9d9fb --- /dev/null +++ b/streamlit_with_external_access/setup.sql @@ -0,0 +1,15 @@ +CREATE DATABASE IF NOT EXISTS ; +CREATE SCHEMA IF NOT EXISTS .; +USE SCHEMA .; + +CREATE SECRET IF NOT EXISTS 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 + ALLOWED_NETWORK_RULES = (streamlit_example_network_rule) + ALLOWED_AUTHENTICATION_SECRETS = () + ENABLED = true; diff --git a/streamlit_with_external_access/snowflake.yml b/streamlit_with_external_access/snowflake.yml new file mode 100644 index 0000000..06723a7 --- /dev/null +++ b/streamlit_with_external_access/snowflake.yml @@ -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: + 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: + external_access_integrations: + - + + deployment_stage: + # Uses context variables to create fully qualified name of stage + stage: <% ctx.env.database %>.<% ctx.env.schema %>. + +env: + schema: + database: diff --git a/streamlit_with_external_access/streamlit_app.py b/streamlit_with_external_access/streamlit_app.py new file mode 100644 index 0000000..e873ef0 --- /dev/null +++ b/streamlit_with_external_access/streamlit_app.py @@ -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) diff --git a/streamlit_with_external_access/template.yml b/streamlit_with_external_access/template.yml new file mode 100644 index 0000000..bfacc2c --- /dev/null +++ b/streamlit_with_external_access/template.yml @@ -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