Source code for cursus.steps.configs.config_redshift_data_loading_step
"""
Redshift Data Loading Step Configuration.
Flattens the SAIS SDK's 3-specification JSON structure (clusterSpecification,
querySpecification, outputSpecification) into Pydantic fields. The computed
property `step_config_json` reassembles the 3-spec dict for the container script.
"""
from typing import Optional, Dict, Any
from pydantic import Field, computed_field, model_validator
from ...core.base.config_base import BasePipelineConfig
[docs]
class RedshiftDataLoadingConfig(BasePipelineConfig):
"""
Configuration for RedshiftDataLoading step.
Source node — executes SQL against Redshift, writes CSV to S3.
Optionally uploads to EDX as side effect.
"""
# ===== Tier 1: Essential (user must provide) =====
cluster_id: str = Field(description="Redshift cluster identifier")
db_name: str = Field(description="Database name")
role_arn: str = Field(description="IAM role ARN for Redshift access")
cluster_endpoint: str = Field(
description="Cluster endpoint hostname (required for pg8000 and Andes3)"
)
query: str = Field(description="SQL query to execute against Redshift")
# ===== Tier 2: System with Defaults =====
connector_type: str = Field(
default="redshift_connector",
description="DB connector: 'pg8000' or 'redshift_connector'",
)
port: int = Field(default=5439, description="Redshift cluster port")
is_using_andes3: bool = Field(
default=True,
description="Use Andes3 IAM authentication with session tags",
)
output_data_source_type: str = Field(
default="S3",
description="Output destination: 'S3' (default, S3 only) or 'EDX' (S3 + EDX upload)",
)
edx_arn: Optional[str] = Field(
default=None,
description="EDX manifest ARN. Required if output_data_source_type='EDX'.",
)
drop_header: bool = Field(
default=False,
description="Whether to drop CSV header in output",
)
job_type: Optional[str] = Field(
default=None,
description="Job type suffix for step naming (e.g., 'mo_orders')",
)
max_runtime_in_seconds: int = Field(
default=43200,
description="Max processing time in seconds (default: 12 hours)",
)
# ===== Validation =====
[docs]
@model_validator(mode="after")
def validate_edx_config(self) -> "RedshiftDataLoadingConfig":
"""Validate EDX ARN is provided when output type is EDX."""
if self.output_data_source_type == "EDX" and not self.edx_arn:
raise ValueError("edx_arn is required when output_data_source_type='EDX'")
if self.connector_type not in ("pg8000", "redshift_connector"):
raise ValueError(
f"connector_type must be 'pg8000' or 'redshift_connector', got '{self.connector_type}'"
)
return self
# ===== Tier 3: Derived =====
@computed_field
@property
def step_config_json(self) -> Dict[str, Any]:
"""
Generate the 3-spec JSON config that the container script reads
from /opt/ml/processing/config/config.
"""
config: Dict[str, Any] = {
"clusterSpecification": {
"clusterId": self.cluster_id,
"dbName": self.db_name,
"roleArn": self.role_arn,
"clusterEndpoint": self.cluster_endpoint,
"port": self.port,
},
"querySpecification": {
"query": self.query,
"connectorType": self.connector_type,
"isUsingAndes3": self.is_using_andes3,
},
"outputSpecification": {},
}
if self.output_data_source_type == "EDX":
config["outputSpecification"] = {
"dataSourceType": "EDX",
"edxArn": self.edx_arn,
"dropHeader": self.drop_header,
}
elif self.drop_header:
config["outputSpecification"] = {"dropHeader": True}
return config