All skills
aws avatar

/ingesting-into-data-lake

@b33847d

Import data into the AWS data lake from S3 files, local uploads, JDBC databases (Oracle, SQL Server, PostgreSQL, MySQL, RDS, Aurora), Amazon Redshift, Snowflake, BigQuery, DynamoDB, or existing Glue catalog tables (migration). Default target is S3 Tables; standard Iceberg on a general purpose bucket is supported where S3 Tables is not adopted. Handles one-time loads, recurring pipelines, migrations. Triggers on: import data, load data, ingest, sync database, migrate table, move data to AWS, set up pipeline, ETL, pull from Snowflake, query BigQuery into S3, export DynamoDB, CTAS, convert to Iceberg. Do NOT use for setting up or troubleshooting Glue connections (use connecting-to-data-source), creating empty tables (use creating-data-lake-table), running queries (use querying-data-lake), finding tables by fuzzy name (use finding-data-lake-assets), catalog audit (use exploring-data-catalog), or SaaS platforms like Salesforce, ServiceNow, SAP, MongoDB, Kafka.

Use this Skill: https://skilld.dev/gh/aws/agent-toolkit-for-aws/ingesting-into-data-lake

This session only. Nothing lands on disk.

referencesglue-etl-migration.md

≈1.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Glue ETL Migration for Large Tables

Use Glue ETL (Path B) when Athena CTAS would time out, when transforms are complex, or when the migration needs to be scheduled/repeatable.

When to Use

  • Source table over ~100 GB
  • Complex column transformations that benefit from PySpark
  • Migration needs to be scheduled or repeatable
  • Source has more than 100 target partitions and batching is impractical

Job Setup

Requirements

  • Glue 5.1 or higher (Spark 3.5.6, Iceberg 1.10.0)
  • --datalake-formats iceberg job argument
  • Catalog config in --conf job argument (not spark.conf.set()). See iceberg-catalog-config-and-usage.md for the exact keys.
  • IAM role with S3 Tables, Glue, and S3 permissions

Job Configuration (JSON)

Use --cli-input-json to avoid shell escaping issues:

Glue --conf format: In Glue DefaultArguments, multiple Spark configs must be passed as a single --conf value with space-separated --conf key=value pairs. Do not split them into separate JSON keys — Glue only reads one --conf key.

{
    "Name": "migrate-to-s3tables",
    "Role": "arn:aws:iam::<account-id>:role/<glue-role>",
    "Command": {
        "Name": "glueetl",
        "ScriptLocation": "s3://<scripts-bucket>/scripts/migrate.py",
        "PythonVersion": "3"
    },
    "DefaultArguments": {
        "--datalake-formats": "iceberg",
        "--enable-glue-datacatalog": "true",
        "--conf": "<see iceberg-catalog-config-and-usage.md for S3 Tables Analytics Integration or REST config>"
    },
    "GlueVersion": "5.1",
    "NumberOfWorkers": 10,
    "WorkerType": "G.1X"
}
aws glue create-job --cli-input-json file://job-config.json --region <region>

Scale NumberOfWorkers based on source size: ~2 workers per 50 GB as a starting point.

PySpark Migration Script

import sys
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job

args = getResolvedOptions(sys.argv, [
    'JOB_NAME', 'source_database', 'source_table',
    'target_namespace', 'target_table'
])

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)

# Read from source (Glue Data Catalog)
source_df = spark.read.table(
    f"glue_catalog.{args['source_database']}.{args['source_table']}"
)

# Apply transforms (customize as needed)
# Example: lowercase column names for S3 Tables compatibility
for col_name in source_df.columns:
    if col_name != col_name.lower():
        source_df = source_df.withColumnRenamed(col_name, col_name.lower())

# Write to S3 Table
target_table = f"s3tablescatalog.{args['target_namespace']}.{args['target_table']}"

source_df.writeTo(target_table) \
    .tableProperty("format-version", "2") \
    .createOrReplace()

# Verify row count
source_count = spark.read.table(
    f"glue_catalog.{args['source_database']}.{args['source_table']}"
).count()
target_count = spark.read.table(target_table).count()
print(f"Source rows: {source_count}, Target rows: {target_count}")

job.commit()

Key Points

  • All catalog config goes in --conf job argument, never in spark.conf.set(). See iceberg-catalog-config-and-usage.md for the exact keys.
  • No LOCATION clause -- S3 Tables manages storage
  • Column names must be all lowercase for Athena visibility
  • createOrReplace() handles both cases: creates the table if absent, replaces it if present (safe for re-runs)
  • For partitioned writes, add .partitionedBy() before .createOrReplace()

Running and Monitoring

# Start the job
JOB_RUN_ID=$(aws glue start-job-run \
  --job-name "migrate-to-s3tables" \
  --arguments '{"--source_database":"legacy_db","--source_table":"orders","--target_namespace":"analytics","--target_table":"orders"}' \
  --query 'JobRunId' --output text)

# Check status
aws glue get-job-run --job-name "migrate-to-s3tables" --run-id "$JOB_RUN_ID"

Troubleshooting

Problem Cause Fix
"Cannot modify static config" Catalog config in spark.conf.set() Move all catalog config to --conf job argument
"Access Denied" on S3 Tables Missing IAM permissions Add AmazonS3TablesFullAccess to Glue role
Job runs out of memory Too few workers for data size Increase NumberOfWorkers or use G.2X worker type
Table not visible in Athena after Glue job Used REST endpoint instead of analytics integration Use the GlueCatalog method with glue.id config

Source: SKILL.md on GitHub

2 warnings17d3 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    This skill facilitates the ingestion of data from various external sources into an AWS data lake. It contains security considerations related to the processing of untrusted data and the dynamic generation of Spark scripts, which are characteristic of ETL (Extract, Transform, Load) operations. These patterns are consistent with the skill's purpose and are used within a managed cloud environment.

  • Socket17d

    1 alert: gptAnomaly

  • Snyk17d

    Risk: MEDIUM · 1 issue

Signed by skilld at b33847d. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 2 months ago
Other metadata
metadata
{
  "version": "1",
  "argument-hint": "'[source-path|connection-name|table-name] [--target s3-tables|iceberg|parquet]'"
}

README badge

README badge for aws/agent-toolkit-for-aws/ingesting-into-data-lake