Using Snowflake data hosted in GCP with AWS Glue
Tags: aws, glue, snowflake
Published: 2024-01-29 18:37:51

This post covers a use case of accessing data held in a Snowflake database hosted in GCP within an AWS Glue ETL job.


## What is Snowflake?

[Snowflake](https://www.snowflake.com) is a cloud-based data warehousing platform that provides a fully managed and scalable solution for storing and analyzing large volumes of data. It is not a traditional relational database but rather a data warehouse as a service. Snowflake is designed to work with cloud platforms like Amazon Web Services (AWS), Microsoft Azure, and Google Cloud Platform (GCP).

## What is AWS Glue?

[AWS Glue](https://aws.amazon.com/glue) is a fully managed extract, transform, and load (ETL) service provided by Amazon Web Services (AWS). It is designed to make it easy for users to prepare and load their data for analysis. AWS Glue simplifies the process of building and managing ETL workflows by providing a serverless environment for running ETL jobs.

## Snowflake Prerequisites

As I wasn't a user of Snowflake already I [signed up for a free trial](https://signup.snowflake.com/) in order to work on this use case.  The process was simple and I didn't need to provide any form of payment to try it out. Well done Snowflake!

## Test Data

I generated some test data to load into Snowflake using [Mockaroo](https://mockaroo.com)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ndzn7rhbnhbjig8bjbny.png)

## Snowflake Setup

Within Snowflake I created a [database, schema](https://docs.snowflake.com/en/sql-reference/ddl-database) and a [warehouse](https://docs.snowflake.com/en/user-guide/warehouses-overview).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4awpt2spgjmbugqty089.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fyj4f1x86kjcsie37yt4.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2oginair0h516pz2g677.png)

With these things in place I loaded the data from my Mockaroo generated JSON file into a new table.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u88j1nqytgol5j1exf5n.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8v6otmg8enoh0ctiqp5t.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nniwjn0mu8av0jenaw14.png)


The data is now able to be queried.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/grja9xrvjf5ab2r9wlul.png)


Next I created the required user and role for Glue to use to connect to Snowflake.

Create a role called car_sales.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ci41nk648u3azxn347o3.png)

Execute the SQL below to assign privileges to the new role.

```
grant select on table matt.matt.car_sales to role car_sales;

grant usage on database matt to role car_sales;

grant usage on schema matt to role car_sales;

grant usage on warehouse matt to role car_sales;
```

Create a user for Glue to connect to - ensure you set the default warehouse and assign the car_sales role.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nlodnsk4xygvuzai4gvs.png)


## AWS Glue Setup

Create an IAM role for the Glue job to execute. Note Glue will need to be able to access Secrets Manager.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hk1ezyzwk7cy6kwdncln.png)


In Secrets Manager create a secret.

Select Other type of secret. For the keys use sfUser, sfPassword and sfWarehouse.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6l43s27mxd6iopsibg9w.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dflt3upqf9m45zvuq2ts.png)


Now in Glue create a Data connection to Snowflake



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hbucd8pi4flp383qtmee.png)




![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w70na04o1baq1equcsny.png)



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1t2i2u8yy0lsnpawv6i.png)


You can find your Snowflake URL in Snowflake by 
selecting Admin > Accounts > . . . Manage URLs

For the AWS Secret, select the one you created earlier.

Give your connection a sensible name.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tf929xeexydvgm1b6vf3.png)


## Extract Snowflake Data with Glue ETL

Create a new Visual ETL job in Glue.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ro931eanaop3xm2x08tp.png)


From Sources select Snowflake


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jc99d0n6jj4pft7g8s2.png)


On data source properties complete the details as shown.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5s4qp25esaunysllhbk4.png)


Test the connections working by selecting the Snowflake connection in the Visual. This will open the Data preview window. Select the role created earlier. This will start a data preview and display a sample of the data from Snowflake. This will take a few minutes to run.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cdumq3bvxdx5sa5s40ru.png)




Within activity in Snowflake you will see the query has been executed by the GLUE user.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/htsxs3cca3ie0akwjdax.png)






You can continue to complete your ETL job within Glue. For example if I only want cars made by Porsche I could add an SQL transformation step.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6z03ld2xiijnzsdxgz4d.png)





Selecting the Script tab provides the Glue ETL code for the job.

```
import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job
from awsglue import DynamicFrame


def sparkSqlQuery(glueContext, query, mapping, transformation_ctx) -> DynamicFrame:
    for alias, frame in mapping.items():
        frame.toDF().createOrReplaceTempView(alias)
    result = spark.sql(query)
    return DynamicFrame.fromDF(result, glueContext, transformation_ctx)


args = getResolvedOptions(sys.argv, ["JOB_NAME"])
sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args["JOB_NAME"], args)

# Script generated for node Snowflake
Snowflake_node1706530098901 = glueContext.create_dynamic_frame.from_options(
    connection_type="snowflake",
    connection_options={
        "autopushdown": "on",
        "dbtable": "car_sales",
        "connectionName": "snowflake_glue_connection",
        "sfDatabase": "matt",
        "sfSchema": "matt",
    },
    transformation_ctx="Snowflake_node1706530098901",
)

# Script generated for node SQL Query
SqlQuery0 = """
select * from myDataSource
where car_make = 'Porsche'
"""
SQLQuery_node1706531170324 = sparkSqlQuery(
    glueContext,
    query=SqlQuery0,
    mapping={"myDataSource": Snowflake_node1706530098901},
    transformation_ctx="SQLQuery_node1706531170324",
)

job.commit()
```

## Conclusion

The cloud provider used for hosting Snowflake makes little difference to the easy integration of Snowflake as a data source in Glue ETL jobs.

The low code / no code interface for building ETL jobs with Glue makes it simple to gather data from many sources once initial IAM, secrets and connections are in place.