

# AWS Glue에서 블루프린트 개발
<a name="developing-blueprints"></a>

AWS Glue 개발자는 데이터 분석가가 워크플로를 생성하는 데 사용할 수 있는 블루프린트를 생성하고 게시할 수 있습니다.

**Topics**
+ [블루프린트 개발 개요](developing-blueprints-overview.md)
+ [블루프린트 개발을 위한 사전 조건](developing-blueprints-prereq.md)
+ [블루프린트 코드 작성](developing-blueprints-code.md)
+ [샘플 블루프린트 프로젝트](developing-blueprints-sample.md)
+ [블루프린트 테스트](developing-blueprints-testing.md)
+ [블루프린트 게시](developing-blueprints-publishing.md)
+ [AWS Glue 블루프린트 클래스 참조](developing-blueprints-code-classes.md)
+ [블루프린트 샘플](developing-blueprints-samples.md)

**다음 사항도 참조하세요.**  
[AWS Glue의 블루프린트 개요](blueprints-overview.md)

# 블루프린트 개발 개요
<a name="developing-blueprints-overview"></a>

개발 프로세스의 첫 번째 단계는 블루프린트의 이점을 얻을 수 있는 일반적인 사용 사례를 파악하는 것입니다. 일반적인 사용 사례에는 일반적인 방식으로 해결해야 한다고 생각하는 반복적인 ETL 문제가 포함됩니다. 다음으로 일반화된 사용 사례를 구현하는 블루프린트를 설계하고 일반화된 사용 사례에서 특정 사용 사례를 정의할 수 있는 블루프린트 입력 파라미터를 정의합니다.

블루프린트는 블루프린트 파라미터 구성 파일이 포함된 프로젝트와 생성할 워크플로의 *레이아웃*을 정의하는 스크립트로 구성됩니다. 레이아웃은 생성할 작업 및 크롤러(또는 블루프린트 스크립트 용어의 *엔터티*)를 정의합니다.

레이아웃 스크립트에서 트리거를 직접 지정하지 않습니다. 대신 스크립트가 생성하는 작업과 크롤러 간의 종속성을 지정하는 코드를 작성합니다. AWS Glue에서는 종속성 사양에 따라 트리거를 생성합니다. 레이아웃 스크립트의 출력은 모든 워크플로 엔터티에 대한 사양을 포함하는 워크플로 객체입니다.

다음 AWS Glue 블루프린트 라이브러리를 사용하여 워크플로 객체를 구축합니다.
+ `awsglue.blueprint.base_resource` - 라이브러리에서 사용하는 기본 리소스의 라이브러리입니다.
+ `awsglue.blueprint.workflow` - `Workflow` 클래스를 정의하기 위한 라이브러리입니다.
+ `awsglue.blueprint.job` - `Job` 클래스를 정의하기 위한 라이브러리입니다.
+ `awsglue.blueprint.crawler` - `Crawler` 클래스를 정의하기 위한 라이브러리입니다.

레이아웃 생성을 위해 지원되는 유일한 다른 라이브러리는 Python 셸에 사용할 수 있는 라이브러리입니다.

블루프린트를 게시하기 전에 블루프린트 라이브러리에 정의된 방법을 사용하여 블루프린트를 로컬에서 테스트할 수 있습니다.

데이터 분석가에게 블루프린트를 제공할 준비가 되면 스크립트, 파라미터 구성 파일, 지원 파일(예: 추가 스크립트 및 라이브러리)을 배포 가능한 단일 자산으로 패키징합니다. 그런 다음 자산을 Amazon S3에 업로드하고 관리자에게 AWS Glue에 등록하도록 요청합니다.

추가 샘플 블루프린트 프로젝트에 대한 자세한 내용은 [샘플 블루프린트 프로젝트](developing-blueprints-sample.md) 및 [블루프린트 샘플](developing-blueprints-samples.md) 섹션을 참조하세요.

# 블루프린트 개발을 위한 사전 조건
<a name="developing-blueprints-prereq"></a>

블루프린트를 개발하려면 AWS Glue 사용과 Apache Spark ETL 작업 또는 Python 셸 작업을 위한 스크립트 작성에 익숙해야 합니다. 또한 다음 설정 태스크를 완료해야 합니다.
+ 블루프린트 레이아웃 스크립트에 사용할 4개의 AWS Python 라이브러리를 다운로드합니다.
+ AWS SDK를 설정합니다.
+ AWS CLI를 설정합니다.

## Python 라이브러리 다운로드
<a name="prereqs-get-libes"></a>

GitHub에서 다음 라이브러리를 다운로드하고 프로젝트에 설치합니다.
+ [https://github.com/awslabs/aws-glue-blueprint-libs/tree/master/awsglue/blueprint/base\$1resource.py](https://github.com/awslabs/aws-glue-blueprint-libs/tree/master/awsglue/blueprint/base_resource.py)
+ [https://github.com/awslabs/aws-glue-blueprint-libs/tree/master/awsglue/blueprint/workflow.py](https://github.com/awslabs/aws-glue-blueprint-libs/tree/master/awsglue/blueprint/workflow.py)
+ [https://github.com/awslabs/aws-glue-blueprint-libs/tree/master/awsglue/blueprint/crawler.py](https://github.com/awslabs/aws-glue-blueprint-libs/tree/master/awsglue/blueprint/crawler.py)
+ [https://github.com/awslabs/aws-glue-blueprint-libs/tree/master/awsglue/blueprint/job.py](https://github.com/awslabs/aws-glue-blueprint-libs/tree/master/awsglue/blueprint/job.py)

## AWS Java SDK 설정
<a name="prereqs-java-preview-sdk"></a>

AWS Java SDK의 경우 블루프린트용 API가 `jar` 포함된 파일을 추가해야 합니다.

1. 아직 설정하지 않은 경우 AWS SDK for Java를 설정합니다.
   + Java 1.x의 경우 *AWS SDK for Java Developer Guide*의 [Set up the AWS SDK for Java](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-install.html) 지침을 따르세요.
   + Java 2.x의 경우 *AWS SDK for Java 2.x Developer Guide*의 [Setting up the AWS SDK for Java 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup.html) 지침을 따르세요.

1. 블루프린트용 API에 대한 액세스 권한이 있는 클라이언트 `jar` 파일을 다운로드합니다.
   + Java 1.x의 경우: s3://awsglue-custom-blueprints-preview-artifacts/awsglue-java-sdk-preview/AWSGlueJavaClient-1.11.x.jar
   + Java 2.x의 경우: s3://awsglue-custom-blueprints-preview-artifacts/awsglue-java-sdk-v2-preview/AwsJavaSdk-Glue-2.0.jar

1. AWS Java SDK에서 제공하는 AWS Glue 클라이언트를 재정의하려면 Java 클래스 경로 앞에 클라이언트 `jar`를 추가합니다.

   ```
   export CLASSPATH=<path-to-preview-client-jar>:$CLASSPATH
   ```

1. (선택 사항) 다음 Java 애플리케이션으로 SDK를 테스트합니다. 애플리케이션이 빈 목록을 출력해야 합니다.

   `accessKey` 및 `secretKey`를 자격 증명으로 바꾸고 `us-east-1`을 리전으로 바꿉니다.

   ```
   import com.amazonaws.auth.AWSCredentials;
   import com.amazonaws.auth.AWSCredentialsProvider;
   import com.amazonaws.auth.AWSStaticCredentialsProvider;
   import com.amazonaws.auth.BasicAWSCredentials;
   import com.amazonaws.services.glue.AWSGlue;
   import com.amazonaws.services.glue.AWSGlueClientBuilder;
   import com.amazonaws.services.glue.model.ListBlueprintsRequest;
   
   public class App{
       public static void main(String[] args) {
           AWSCredentials credentials = new BasicAWSCredentials("accessKey", "secretKey");
           AWSCredentialsProvider provider = new AWSStaticCredentialsProvider(credentials);
           AWSGlue glue = AWSGlueClientBuilder.standard().withCredentials(provider)
                   .withRegion("us-east-1").build();
           ListBlueprintsRequest request = new ListBlueprintsRequest().withMaxResults(2);
           System.out.println(glue.listBlueprints(request));
       }
   }
   ```

## AWS Python SDK 설정
<a name="prereqs-python-preview-sdk"></a>

다음 단계에서는 컴퓨터에 Python 버전 2.7 이상 또는 버전 3.9 이상이 설치되어 있다고 가정합니다.

1. 다음 boto3 휠 파일을 다운로드합니다. 열거나 저장하라는 메시지가 표시되면 s3://awsglue-custom-blueprints-preview-artifacts/aws-python-sdk-preview/boto3-1.17.31-py2.py3-none-any.whl 파일을 저장합니다.

1. botocore 휠 파일인 s3://awsglue-custom-blueprints-preview-artifacts/aws-python-sdk-preview/botocore-1.20.31-py2.py3-none-any.whl을 다운로드합니다.

1. Python 버전을 확인합니다.

   ```
   python --version
   ```

1. Python 버전에 따라 다음 명령을 입력합니다(Linux의 경우).
   + Python 2.7 이상용입니다.

     ```
     python3 -m pip install --user virtualenv
     source env/bin/activate
     ```
   + Python 3.9 이상용입니다.

     ```
     python3 -m venv python-sdk-test
     source python-sdk-test/bin/activate
     ```

1. botocore 휠 파일을 설치합니다.

   ```
   python3 -m pip install <download-directory>/botocore-1.20.31-py2.py3-none-any.whl
   ```

1. boto3 휠 파일을 설치합니다.

   ```
   python3 -m pip install <download-directory>/boto3-1.17.31-py2.py3-none-any.whl
   ```

1. `~/.aws/credentials` 및 `~/.aws/config` 파일에서 자격 증명과 기본 리전을 구성합니다. 자세한 내용은 *AWS Command Line Interface User Guide*의 [Configuring the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html)를 참조하세요.

1. (선택 사항) 설정을 테스트합니다. 다음 명령은 빈 목록을 반환합니다.

   `us-east-1`을 해당 리전으로 바꿉니다.

   ```
   $ python
   >>> import boto3
   >>> glue = boto3.client('glue', 'us-east-1')
   >>> glue.list_blueprints()
   ```

## 미리 보기 AWS CLI 설정
<a name="prereqs-setup-cli"></a>

1. 아직 수행하지 않았다면 컴퓨터에 AWS Command Line Interface(AWS CLI)를 설치 및/또는 업데이트합니다. 이를 수행하는 가장 쉬운 방법은 Python 설치 프로그램 유틸리티인 `pip`를 사용하는 것입니다.

   ```
   pip install awscli --upgrade --user
   ```

   AWS CLI에 대한 전체 설치 지침은 [AWS Command Line Interface 설치](https://docs.aws.amazon.com/cli/latest/userguide/installing.html)에서 찾을 수 있습니다.

1. s3://awsglue-custom-blueprints-preview-artifacts/awscli-preview-build/awscli-1.19.31-py2.py3-none-any.whl에서 AWS CLI 휠 파일을 다운로드합니다.

1. AWS CLI 휠 파일을 설치합니다.

   ```
   python3 -m pip install awscli-1.19.31-py2.py3-none-any.whl
   ```

1. `aws configure` 명령을 실행합니다. AWS 자격 증명(액세스 키 및 보안 암호 키 포함) 및 AWS 리전을 구성합니다. AWS CLI 구성에 대한 자세한 내용은 [AWS CLI 구성](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html)에서 찾을 수 있습니다.

1. AWS CLI를 테스트합니다. 다음 명령은 빈 목록을 반환합니다.

   `us-east-1`을 해당 리전으로 바꿉니다.

   ```
   aws glue list-blueprints --region us-east-1
   ```

# 블루프린트 코드 작성
<a name="developing-blueprints-code"></a>

생성하는 각 블루프린트 프로젝트에는 최소한 다음 파일이 포함되어야 합니다.
+ 워크플로를 정의하는 Python 레이아웃 스크립트. 스크립트에는 워크플로의 엔터티(작업 및 크롤러)와 이들 간의 종속성을 정의하는 기능이 포함되어 있습니다.
+ 다음을 정의하는 구성 파일, `blueprint.cfg` 
  + 워크플로 레이아웃 정의 기능의 전체 경로.
  + 블루프린트에서 허용하는 파라미터.

**Topics**
+ [블루프린트 레이아웃 스크립트 생성](developing-blueprints-code-layout.md)
+ [구성 파일 생성](developing-blueprints-code-config.md)
+ [블루프린트 파라미터 지정](developing-blueprints-code-parameters.md)

# 블루프린트 레이아웃 스크립트 생성
<a name="developing-blueprints-code-layout"></a>

블루프린트 레이아웃 스크립트에는 워크플로에서 엔터티를 생성하는 함수가 포함되어야 합니다. 원하는 대로 이 함수의 이름을 지정할 수 있습니다. AWS Glue에서는 구성 파일을 사용하여 함수의 정규화된 이름을 확인합니다.

레이아웃 함수는 다음을 수행합니다.
+ (선택 사항) `Job` 클래스를 인스턴스화하여 `Job` 객체를 생성하고 `Command` 및 `Role` 등의 인수를 전달합니다. AWS Glue 콘솔 또는 API를 사용하여 작업을 생성하는 경우 지정할 작업 속성입니다.
+ (선택 사항) `Crawler` 클래스를 인스턴스화하여 `Crawler` 객체를 생성하고 이름, 역할 및 대상 인수를 전달합니다.
+ 객체(워크플로 엔터티) 간의 종속성을 나타내려면 `DependsOn` 및 `WaitForDependencies` 추가 인수를 `Job()` 및 `Crawler()`에 전달합니다. 이러한 인수는 이 섹션의 뒷부분에서 설명합니다.
+ `Workflow` 클래스를 인스턴스화하여 AWS Glue에 반환되는 워크플로 객체를 생성하고 `Name` 인수, `Entities` 인수, 선택적 `OnSchedule` 인수를 전달합니다. 이 `Entities` 인수는 워크플로에 포함할 모든 작업 및 크롤러를 지정합니다. `Entities` 객체를 구성하는 방법을 보려면 이 섹션의 뒷부분에 나오는 샘플 프로젝트를 참조하세요.
+ `Workflow` 객체를 반환합니다.

`Job`, `Crawler` 및 `Workflow` 클래스의 정의는 [AWS Glue 블루프린트 클래스 참조](developing-blueprints-code-classes.md) 섹션을 참조하세요.

레이아웃 함수에 사용할 수 있는 입력 인수는 다음과 같습니다.


| 인수 | 설명 | 
| --- | --- | 
| user\$1params | 블루프린트 파라미터 이름 및 값의 Python 딕셔너리. 자세한 내용은 [블루프린트 파라미터 지정](developing-blueprints-code-parameters.md) 섹션을 참조하세요. | 
| system\$1params | 두 가지 속성(region 및 accountId)을 포함하는 Python 딕셔너리. | 

다음은 `Layout.py`라는 파일의 샘플 레이아웃 생성기 스크립트입니다.

```
import argparse
import sys
import os
import json
from awsglue.blueprint.workflow import *
from awsglue.blueprint.job import *
from awsglue.blueprint.crawler import *


def generate_layout(user_params, system_params):

    etl_job = Job(Name="{}_etl_job".format(user_params['WorkflowName']),
                  Command={
                      "Name": "glueetl",
                      "ScriptLocation": user_params['ScriptLocation'],
                      "PythonVersion": "2"
                  },
                  Role=user_params['PassRole'])
    post_process_job = Job(Name="{}_post_process".format(user_params['WorkflowName']),
                            Command={
                                "Name": "pythonshell",
                                "ScriptLocation": user_params['ScriptLocation'],
                                "PythonVersion": "2"
                            },
                            Role=user_params['PassRole'],
                            DependsOn={
                                etl_job: "SUCCEEDED"
                            },
                            WaitForDependencies="AND")
    sample_workflow = Workflow(Name=user_params['WorkflowName'],
                            Entities=Entities(Jobs=[etl_job, post_process_job]))
    return sample_workflow
```

샘플 스크립트는 필요한 Blueprint 라이브러리를 가져오고 2개의 작업으로 워크플로를 생성하는 `generate_layout` 함수를 포함합니다. 이것은 매우 간단한 스크립트입니다. 보다 복잡한 스크립트는 추가 로직 및 파라미터를 사용하여 많은 작업과 크롤러 또는 다양한 수의 작업과 크롤러가 있는 워크플로를 생성할 수 있습니다.

## DependsOn 인수 사용
<a name="developing-blueprints-code-layout-depends-on"></a>

`DependsOn` 인수는 이 엔터티가 워크플로 내의 다른 엔터티에 대해 갖는 종속성의 딕셔너리 표현입니다. 형식은 다음과 같습니다.

```
DependsOn = {dependency1 : state, dependency2 : state, ...}
```

이 딕셔너리의 키는 엔터티의 이름이 아닌 객체 참조를 나타내는 반면 값은 감시할 상태에 해당하는 문자열입니다. AWS Glue는 적절한 트리거를 유추합니다. 유효한 상태는 [조건 구조](https://docs.aws.amazon.com/glue/latest/dg/aws-glue-api-jobs-trigger.html#aws-glue-api-jobs-trigger-Condition)를 참조하세요.

예를 들어 작업은 크롤러의 성공적인 완료에 따라 달라질 수 있습니다. 다음과 같이 이름이 `crawler2`인 크롤러 객체를 정의하는 경우

```
crawler2 = Crawler(Name="my_crawler", ...)
```

그러면 `crawler2`에 종속된 객체에는 다음과 같은 생성자 인수가 포함됩니다.

```
DependsOn = {crawler2 : "SUCCEEDED"}
```

예:

```
job1 = Job(Name="Job1", ..., DependsOn = {crawler2 : "SUCCEEDED", ...})
```

엔터티에 대해 `DependsOn`이 생략된 경우 해당 엔터티는 워크플로 시작 트리거에 따라 달라집니다.

## WaitForDependencies 인수 사용
<a name="developing-blueprints-code-layout-wait-for-dependencies"></a>

`WaitForDependencies` 인수는 작업 또는 크롤러 엔터티가 종속된 *모든* 엔터티가 완료될 때까지 또는 *하나라도*완료될 때까지 기다려야 하는지 여부를 정의합니다.

허용되는 값은 "`AND`" 또는 "`ANY`"입니다.

## OnSchedule 인수 사용
<a name="developing-blueprints-code-layout-on-schedule"></a>

`Workflow` 클래스 생성자의 `OnSchedule` 인수는 워크플로에 대한 시작 트리거 정의를 정의하는 `cron` 표현식입니다.

이 인수가 지정되면 AWS Glue는 해당 일정으로 일정 트리거를 생성합니다. 지정되지 않은 경우 워크플로의 시작 트리거는 온디맨드 트리거입니다.

# 구성 파일 생성
<a name="developing-blueprints-code-config"></a>

블루프린트 구성 파일은 워크플로 생성을 위한 스크립트 진입점과 블루프린트에서 허용하는 파라미터를 정의하는 필수 파일입니다. 파일의 이름은 `blueprint.cfg`여야 합니다.

다음은 샘플 구성 파일입니다.

```
{
    "layoutGenerator": "DemoBlueprintProject.Layout.generate_layout",
    "parameterSpec" : {
           "WorkflowName" : {
                "type": "String",
                "collection": false
           },
           "WorkerType" : {
                "type": "String",
                "collection": false,
                "allowedValues": ["G1.X", "G2.X"],
                "defaultValue": "G1.X"
           },
           "Dpu" : {
                "type" : "Integer",
                "allowedValues" : [2, 4, 6],
                "defaultValue" : 2
           },
           "DynamoDBTableName": {
                "type": "String",
                "collection" : false
           },
           "ScriptLocation" : {
                "type": "String",
                "collection": false
    	}
    }
}
```

`layoutGenerator` 속성은 레이아웃을 생성하는 스크립트에서 함수의 정규화된 이름을 지정합니다.

`parameterSpec` 속성은 이 블루프린트에서 허용하는 파라미터를 지정합니다. 자세한 내용은 [블루프린트 파라미터 지정](developing-blueprints-code-parameters.md) 섹션을 참조하세요.

**중요**  
구성 파일에 워크플로 이름이 블루프린트 파라미터로 포함되거나 레이아웃 스크립트에서 고유한 워크플로 이름을 생성해야 합니다.

# 블루프린트 파라미터 지정
<a name="developing-blueprints-code-parameters"></a>

구성 파일에는 `parameterSpec` JSON 객체의 블루프린트 파라미터 사양이 포함되어 있습니다. `parameterSpec`은 하나 이상의 파라미터 객체를 포함합니다.

```
"parameterSpec": {
    "<parameter_name>": {
      "type": "<parameter-type>",
      "collection": true|false, 
      "description": "<parameter-description>",
      "defaultValue": "<default value for the parameter if value not specified>"
      "allowedValues": "<list of allowed values>" 
    },
    "<parameter_name>": {    
       ...
    }
  }
```

다음은 각 파라미터 객체를 코딩하는 규칙입니다.
+ 파라미터 이름과 `type`은 필수입니다. 다른 모든 속성은 선택 사항입니다.
+ `defaultValue` 속성을 지정하는 경우 파라미터는 선택 사항입니다. 그렇지 않으면 파라미터가 필수이며 블루프린트에서 워크플로를 생성하는 데이터 분석가가 해당 값을 제공해야 합니다.
+ `collection` 속성을 `true`로 설정하면 파라미터가 값 컬렉션을 사용할 수 있습니다. 컬렉션은 모든 데이터 유형이 될 수 있습니다.
+ `allowedValues`를 지정하면 AWS Glue 콘솔에 데이터 분석가가 블루프린트에서 워크플로를 생성할 때 선택할 수 있는 값의 드롭다운 목록이 표시됩니다.

다음은 `type`에 허용되는 값입니다.


| 파라미터 데이터 유형 | 참고 | 
| --- | --- | 
| String | - | 
| Integer | - | 
| Double | - | 
| Boolean | 가능한 값은 true 및 false입니다. AWS Glue 콘솔의 <블루프린트> 페이지에서 워크플로 생성(Create a workflow from <blueprint>) 페이지에 확인란을 생성합니다. | 
| S3Uri | s3://로 시작하여 Amazon S3 경로를 완성합니다. [<블루프린트>에서 워크플로 생성(Create a workflow from <blueprint>)]에서 텍스트 필드와 [찾아보기(Browse)] 버튼을 생성합니다. | 
| S3Bucket | Amazon S3 버킷 이름만입니다. <블루프린트>에서 워크플로 생성(Create a workflow from <blueprint>) 페이지에서 버킷 선택기를 생성합니다. | 
| IAMRoleArn | AWS Identity and Access Management(IAM) 역할의 Amazon 리소스 이름(ARN)입니다. <블루프린트>에서 워크플로 생성(Create a workflow from <blueprint>) 페이지에서 역할 선택기를 생성합니다. | 
| IAMRoleName | IAM 역할의 이름입니다. <블루프린트>에서 워크플로 생성(Create a workflow from <blueprint>) 페이지에서 역할 선택기를 생성합니다. | 

# 샘플 블루프린트 프로젝트
<a name="developing-blueprints-sample"></a>

데이터 포맷 변환은 빈번한 추출, 변환, 로드 사용 사례입니다. 일반적인 분석 워크로드에서는 Parquet 또는 ORC와 같은 열 기반 파일 포맷이 CSV 또는 JSON과 같은 텍스트 포맷보다 선호됩니다. 이 샘플 블루프린트를 사용하면 CSV/JSON 등의 데이터를 Amazon S3의 파일용 Parquet로 변환할 수 있습니다.

이 블루프린트는 블루프린트 파라미터로 정의된 S3 경로 목록을 가져와 데이터를 Parquet 포맷으로 변환한 다음 다른 블루프린트 파라미터로 지정된 S3 위치에 씁니다. 레이아웃 스크립트는 각 경로에 대한 크롤러 및 작업을 생성합니다. 또한 레이아웃 스크립트는 `Conversion.py`의 ETL 스크립트를 다른 블루프린트 파라미터로 지정된 S3 버킷에 업로드합니다. 그런 다음 레이아웃 스크립트는 업로드된 스크립트를 각 작업에 대한 ETL 스크립트로 지정합니다. 프로젝트의 ZIP 아카이브에는 레이아웃 스크립트, ETL 스크립트 및 Blueprint 구성 파일이 포함되어 있습니다.

추가 샘플 블루프린트 프로젝트에 대한 자세한 내용은 [블루프린트 샘플](developing-blueprints-samples.md) 섹션을 참조하세요.

다음은 `Layout.py` 파일에 있는 레이아웃 스크립트입니다.

```
from awsglue.blueprint.workflow import *
from awsglue.blueprint.job import *
from awsglue.blueprint.crawler import *
import boto3

s3_client = boto3.client('s3')

# Ingesting all the S3 paths as Glue table in parquet format
def generate_layout(user_params, system_params):
    #Always give the full path for the file
    with open("ConversionBlueprint/Conversion.py", "rb") as f:
        s3_client.upload_fileobj(f, user_params['ScriptsBucket'], "Conversion.py")
    etlScriptLocation = "s3://{}/Conversion.py".format(user_params['ScriptsBucket'])    
    crawlers = []
    jobs = []
    workflowName = user_params['WorkflowName']
    for path in user_params['S3Paths']:
      tablePrefix = "source_" 
      crawler = Crawler(Name="{}_crawler".format(workflowName),
                        Role=user_params['PassRole'],
                        DatabaseName=user_params['TargetDatabase'],
                        TablePrefix=tablePrefix,
                        Targets= {"S3Targets": [{"Path": path}]})
      crawlers.append(crawler)
      transform_job = Job(Name="{}_transform_job".format(workflowName),
                         Command={"Name": "glueetl",
                                  "ScriptLocation": etlScriptLocation,
                                  "PythonVersion": "3"},
                         Role=user_params['PassRole'],
                         DefaultArguments={"--database_name": user_params['TargetDatabase'],
                                           "--table_prefix": tablePrefix,
                                           "--region_name": system_params['region'],
                                           "--output_path": user_params['TargetS3Location']},
                         DependsOn={crawler: "SUCCEEDED"},
                         WaitForDependencies="AND")
      jobs.append(transform_job)
    conversion_workflow = Workflow(Name=workflowName, Entities=Entities(Jobs=jobs, Crawlers=crawlers))
    return conversion_workflow
```

다음은 해당 블루프린트 구성 파일인 `blueprint.cfg`입니다.

```
{
    "layoutGenerator": "ConversionBlueprint.Layout.generate_layout",
    "parameterSpec" : {
        "WorkflowName" : {
            "type": "String",
            "collection": false,
            "description": "Name for the workflow."
        },
        "S3Paths" : {
            "type": "S3Uri",
            "collection": true,
            "description": "List of Amazon S3 paths for data ingestion."
        },
        "PassRole" : {
            "type": "IAMRoleName",
            "collection": false,
            "description": "Choose an IAM role to be used in running the job/crawler"
        },
        "TargetDatabase": {
            "type": "String",
            "collection" : false,
            "description": "Choose a database in the Data Catalog."
        },
        "TargetS3Location": {
            "type": "S3Uri",
            "collection" : false,
            "description": "Choose an Amazon S3 output path: ex:s3://<target_path>/."
        },
        "ScriptsBucket": {
            "type": "S3Bucket",
            "collection": false,
            "description": "Provide an S3 bucket name(in the same AWS Region) to store the scripts."
        }
    }
}
```

`Conversion.py` 파일의 다음 스크립트는 업로드된 ETL 스크립트입니다. 변환하는 동안 파티션 구성표를 유지합니다.

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

args = getResolvedOptions(sys.argv, [
    'JOB_NAME',
    'region_name',
    'database_name',
    'table_prefix',
    'output_path'])
databaseName = args['database_name']
tablePrefix = args['table_prefix']
outputPath = args['output_path']

glue = boto3.client('glue', region_name=args['region_name'])

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

def get_tables(database_name, table_prefix):
    tables = []
    paginator = glue.get_paginator('get_tables')
    for page in paginator.paginate(DatabaseName=database_name, Expression=table_prefix+"*"):
        tables.extend(page['TableList'])
    return tables

for table in get_tables(databaseName, tablePrefix):
    tableName = table['Name']
    partitionList = table['PartitionKeys']
    partitionKeys = []
    for partition in partitionList:
        partitionKeys.append(partition['Name'])

    # Create DynamicFrame from Catalog
    dyf = glue_context.create_dynamic_frame.from_catalog(
        name_space=databaseName,
        table_name=tableName,
        additional_options={
            'useS3ListImplementation': True
        },
        transformation_ctx='dyf'
    )

    # Resolve choice type with make_struct
    dyf = ResolveChoice.apply(
        frame=dyf,
        choice='make_struct',
        transformation_ctx='resolvechoice_' + tableName
    )

    # Drop null fields
    dyf = DropNullFields.apply(
        frame=dyf,
        transformation_ctx="dropnullfields_" + tableName
    )

    # Write DynamicFrame to S3 in glueparquet
    sink = glue_context.getSink(
        connection_type="s3",
        path=outputPath,
        enableUpdateCatalog=True,
        partitionKeys=partitionKeys
    )
    sink.setFormat("glueparquet")

    sink.setCatalogInfo(
        catalogDatabase=databaseName,
        catalogTableName=tableName[len(tablePrefix):]
    )
    sink.writeFrame(dyf)

job.commit()
```

**참고**  
2개의 Amazon S3 경로만 샘플 블루프린트에 대한 입력으로 제공될 수 있습니다. 이는 AWS Glue 트리거가 2개의 크롤러 작업만 호출하도록 제한되기 때문입니다.

# 블루프린트 테스트
<a name="developing-blueprints-testing"></a>

코드를 개발하는 동안 워크플로 레이아웃이 올바른지 확인하기 위해 로컬 테스트를 수행해야 합니다.

로컬 테스트는 AWS Glue 작업, 크롤러 또는 트리거를 생성하지 않습니다. 대신 레이아웃 스크립트를 로컬에서 실행하고 `to_json()` 및 `validate()` 메서드를 사용하여 객체를 인쇄하고 오류를 찾습니다. 이러한 방법은 라이브러리에 정의 된 3가지 클래스 모두에서 사용할 수 있습니다.

AWS Glue가 레이아웃 함수에 전달하는 `user_params` 및 `system_params` 인수를 처리하는 두 가지 방법이 있습니다. 테스트 벤치 코드는 샘플 블루프린트 파라미터 값의 딕셔너리를 생성하고 이를 `user_params` 인수로 레이아웃 함수에 전달할 수 있습니다. 또는 `user_params`에 대한 참조를 제거하고 하드코딩된 문자열로 바꿀 수 있습니다.

코드에서 `system_params` 인수의 `region` 및 `accountId` 속성을 사용하는 경우 `system_params`에 대한 딕셔너리를 전달할 수 있습니다.

**블루프린트를 테스트하려면**

1. 라이브러리가 있는 디렉터리에서 Python 인터프리터를 시작하거나 블루프린트 파일과 제공된 라이브러리를 원하는 IDE(통합 개발 환경)로 로드합니다.

1. 코드가 제공된 라이브러리를 가져 오는지 확인합니다.

1. 레이아웃 기능에 코드를 추가하여 엔터티 또는 `Workflow` 객체에서 `validate()` 또는 `to_json()`을 호출합니다. 예를 들어 코드가 `mycrawler`라는 `Crawler` 객체를 생성하는 경우 다음과 같이 `validate()`를 호출할 수 있습니다.

   ```
   mycrawler.validate()
   ```

   다음과 같이 `mycrawler`를 인쇄 할 수 있습니다.

   ```
   print(mycrawler.to_json())
   ```

   객체에서 `to_json`을 호출하면 ` to_json()`이 `validate()`를 호출하기 때문에 `validate()`도 호출할 필요가 없습니다.

   워크플로 객체에서 이러한 메서드를 호출하는 것이 가장 유용합니다. 스크립트가 워크플로 객체의 이름을 `my_workflow`라고 가정하고 다음과 같이 워크플로 객체를 검증하고 인쇄합니다.

   ```
   print(my_workflow.to_json())
   ```

   `to_json()` 및 `validate()`에 대한 자세한 내용은 [클래스 메서드](developing-blueprints-code-classes.md#developing-blueprints-code-methods)섹션을 참조하세요.

   이 섹션의 뒷부분에 나오는 예제와 같이 `pprint`를 가져와서 워크플로 객체를 예쁘게 인쇄할 수도 있습니다.

1. 코드를 실행하고, 오류를 수정하고, 마지막으로 `validate()` 또는 `to_json()`에 대한 호출을 제거합니다.

**Example**  
다음 예제는 샘플 블루프린트 파라미터의 딕셔너리를 구성하고 레이아웃 함수 `generate_compaction_workflow`에 `user_params` 인수로 전달하는 방법을 보여줍니다. 또한 생성된 워크플로 객체를 예쁘게 인쇄하는 방법을 보여줍니다.  

```
from pprint import pprint
from awsglue.blueprint.workflow import *
from awsglue.blueprint.job import *
from awsglue.blueprint.crawler import *
 
USER_PARAMS = {"WorkflowName": "compaction_workflow",
               "ScriptLocation": "s3://amzn-s3-demo-bucket/scripts/threaded-compaction.py",
               "PassRole": "arn:aws:iam::111122223333:role/GlueRole-ETL",
               "DatabaseName": "cloudtrial",
               "TableName": "ct_cloudtrail",
               "CoalesceFactor": 4,
               "MaxThreadWorkers": 200}
 
 
def generate_compaction_workflow(user_params: dict, system_params: dict) -> Workflow:
    compaction_job = Job(Name=f"{user_params['WorkflowName']}_etl_job",
                         Command={"Name": "glueetl",
                                  "ScriptLocation": user_params['ScriptLocation'],
                                  "PythonVersion": "3"},
                         Role="arn:aws:iam::111122223333:role/AWSGlueServiceRoleDefault",
                         DefaultArguments={"DatabaseName": user_params['DatabaseName'],
                                           "TableName": user_params['TableName'],
                                           "CoalesceFactor": user_params['CoalesceFactor'],
                                           "max_thread_workers": user_params['MaxThreadWorkers']})
 
    catalog_target = {"CatalogTargets": [{"DatabaseName": user_params['DatabaseName'], "Tables": [user_params['TableName']]}]}
 
    compacted_files_crawler = Crawler(Name=f"{user_params['WorkflowName']}_post_crawl",
                                      Targets = catalog_target,
                                      Role=user_params['PassRole'],
                                      DependsOn={compaction_job: "SUCCEEDED"},
                                      WaitForDependencies="AND",
                                      SchemaChangePolicy={"DeleteBehavior": "LOG"})
 
    compaction_workflow = Workflow(Name=user_params['WorkflowName'],
                                   Entities=Entities(Jobs=[compaction_job],
                                                     Crawlers=[compacted_files_crawler]))
    return compaction_workflow
 
generated = generate_compaction_workflow(user_params=USER_PARAMS, system_params={})
gen_dict = generated.to_json()
 
pprint(gen_dict)
```

# 블루프린트 게시
<a name="developing-blueprints-publishing"></a>

블루프린트를 개발한 후에는 Amazon S3에 업로드해야 합니다. 블루프린트를 게시하는 데 사용하는 Amazon S3 버킷에 대한 쓰기 권한이 있어야 합니다. 또한 블루프린트를 등록할 AWS Glue 관리자에게 Amazon S3 버킷에 대한 읽기 액세스 권한이 있는지 확인해야 합니다. AWS Glue 블루프린트의 페르소나 및 역할에 대해 제안된 AWS Identity and Access Management(IAM) 권한 정책은 [AWS Glue 블루프린트에 대한 페르소나 및 역할의 권한](blueprints-personas-permissions.md) 섹션을 참조하세요.

**블루프린트를 게시하려면**

1. 필요한 스크립트, 리소스 및 블루프린트 구성 파일을 생성합니다.

1. 모든 파일을 ZIP 아카이브에 추가하고 ZIP 파일을 Amazon S3에 업로드합니다. 사용자가 블루프린트를 등록하고 실행할 리전과 동일한 리전에 있는 S3 버킷을 사용합니다.

   다음 명령을 사용하여 명령줄에서 ZIP 파일을 생성할 수 있습니다.

   ```
   zip -r folder.zip folder
   ```

1. 원하는 AWS 계정에 읽기 권한을 부여하는 버킷 정책을 추가합니다. 다음은 샘플 정책입니다.

------
#### [ JSON ]

****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect": "Allow",
         "Principal": {
           "AWS": "arn:aws:iam::111122223333:root"
         },
         "Action": "s3:GetObject",
         "Resource": "arn:aws:s3:::my-blueprints/*"
       }
     ]
   }
   ```

------

1. Amazon S3 버킷에 대한 IAM `s3:GetObject` 권한을 AWS Glue 관리자 또는 블루프린트를 등록할 사람에게 부여합니다. 관리자에게 부여할 샘플 정책은 [블루프린트에 대한 AWS Glue 관리자 권한](blueprints-personas-permissions.md#bp-persona-admin) 섹션을 참조하세요.

블루프린트의 로컬 테스트를 완료한 후 AWS Glue에서 블루프린트를 테스트할 수도 있습니다. AWS Glue에서 블루프린트를 테스트하려면 등록이 필요합니다. IAM 권한 부여를 사용하거나 별도의 테스트 계정을 사용하여 등록된 블루프린트를 볼 수 있는 사람을 제한할 수 있습니다.

**또한 다음 섹션도 참조하세요.**  
[AWS Glue의 블루프린트 등록](registering-blueprints.md)

# AWS Glue 블루프린트 클래스 참조
<a name="developing-blueprints-code-classes"></a>

AWS Glue 블루프린트용 라이브러리는 워크플로 레이아웃 스크립트에서 사용하는 세 가지 클래스인 `Job`, `Crawler` 및 `Workflow`를 정의합니다.

**Topics**
+ [작업 클래스](#developing-blueprints-code-jobclass)
+ [크롤러 클래스](#developing-blueprints-code-crawlerclass)
+ [워크플로 클래스](#developing-blueprints-code-workflowclass)
+ [클래스 메서드](#developing-blueprints-code-methods)

## 작업 클래스
<a name="developing-blueprints-code-jobclass"></a>

`Job` 클래스는 AWS Glue ETL 작업을 나타냅니다.

**필수 생성자 인수**  
다음은 `Job` 클래스에 대한 필수 생성자 인수입니다.


| 인수 이름 | Type | 설명 | 
| --- | --- | --- | 
| Name | str | 작업에 할당할 이름입니다. AWS Glue는 작업을 다른 블루프린트 실행에서 생성된 작업과 구별하기 위해 이름에 임의로 생성된 접미사를 추가합니다. | 
| Role | str | 실행 중 작업이 수임해야 하는 역할의 Amazon 리소스 이름(ARN)입니다. | 
| Command | dict | API 문서의 [JobCommand 구조](aws-glue-api-jobs-job.md#aws-glue-api-jobs-job-JobCommand)에 지정된 작업 명령. | 

**선택적 생성자 인수**  
다음은 `Job` 클래스에 대한 선택적 생성자 인수입니다.


| 인수 이름 | Type | 설명 | 
| --- | --- | --- | 
| DependsOn | dict | 작업이 종속된 워크플로 엔터티의 목록입니다. 자세한 내용은 [DependsOn 인수 사용](developing-blueprints-code-layout.md#developing-blueprints-code-layout-depends-on) 섹션을 참조하세요. | 
| WaitForDependencies | str | 작업이 종속된 모든 엔터티가 실행되기 전에 완료될 때까지 기다릴지 아니면 하나라도 완료될 때까지 기다릴지 나타냅니다. 자세한 내용은 [WaitForDependencies 인수 사용](developing-blueprints-code-layout.md#developing-blueprints-code-layout-wait-for-dependencies) 섹션을 참조하세요. 작업이 하나의 엔티티에만 종속되는 경우 생략합니다. | 
| (작업 속성) | - | AWS Glue API 설명서의 [작업 구조](aws-glue-api-jobs-job.md#aws-glue-api-jobs-job-Job)에 나열된 모든 작업 속성(CreatedOn 및 LastModifiedOn 제외)입니다. | 

## 크롤러 클래스
<a name="developing-blueprints-code-crawlerclass"></a>

`Crawler` 클래스는 AWS Glue 크롤러를 나타냅니다.

**필수 생성자 인수**  
다음은 `Crawler` 클래스에 대한 필수 생성자 인수입니다.


| 인수 이름 | Type | 설명 | 
| --- | --- | --- | 
| Name | str | 크롤러에 할당할 이름입니다. AWS Glue는 크롤러를 다른 블루프린트 실행에서 생성된 크롤러와 구별하기 위해 이름에 임의로 생성된 접미사를 추가합니다. | 
| Role | str | 크롤러가 실행 중 수임해야 하는 역할의 ARN입니다. | 
| Targets | dict | 크롤링할 대상 컬렉션입니다. Targets 클래스 생성자 인수는 API 문서의 [CrawlerTargets 구조](aws-glue-api-crawler-crawling.md#aws-glue-api-crawler-crawling-CrawlerTargets)에 정의되어 있습니다. 모두 Targets 생성자 인수는 선택 사항이지만 적어도 하나는 전달해야합니다. | 

**선택적 생성자 인수**  
다음은 `Crawler` 클래스에 대한 선택적 생성자 인수입니다.


| 인수 이름 | Type | 설명 | 
| --- | --- | --- | 
| DependsOn | dict | 크롤러가 종속된 워크플로 엔터티의 목록입니다. 자세한 내용은 [DependsOn 인수 사용](developing-blueprints-code-layout.md#developing-blueprints-code-layout-depends-on) 섹션을 참조하세요. | 
| WaitForDependencies | str | 크롤러가 종속된 모든 엔터티가 실행되기 전에 완료될 때까지 기다릴지 아니면 하나라도 완료될 때까지 기다릴지 나타냅니다. 자세한 내용은 [WaitForDependencies 인수 사용](developing-blueprints-code-layout.md#developing-blueprints-code-layout-wait-for-dependencies) 섹션을 참조하세요. 크롤러가 하나의 엔티티에만 종속된 경우에는 생략합니다. | 
| (크롤러 속성) | - | 다음 예외사항과 함께 AWS Glue API 설명서의 [크롤러 구조](aws-glue-api-crawler-crawling.md#aws-glue-api-crawler-crawling-Crawler)에 나열된 모든 크롤러 속성:[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/glue/latest/dg/developing-blueprints-code-classes.html) | 

## 워크플로 클래스
<a name="developing-blueprints-code-workflowclass"></a>

`Workflow` 클래스는 AWS Glue 워크플로를 나타냅니다. 워크플로 레이아웃 스크립트는 `Workflow` 객체를 반환합니다. AWS Glue에서는 이 객체를 기반으로 하여 워크플로를 생성합니다.

**필수 생성자 인수**  
다음은 `Workflow` 클래스에 대한 필수 생성자 인수입니다.


| 인수 이름 | Type | 설명 | 
| --- | --- | --- | 
| Name | str | 워크플로에 할당할 이름입니다. | 
| Entities | Entities | 워크플로에 포함할 엔터티 (작업 및 크롤러)의 컬렉션입니다. Entities 클래스 생성자는 Crawler 객체의 목록인 Crawlers 인수와 Job 객체의 목록인 Jobs 인수를 허용합니다. | 

**선택적 생성자 인수**  
다음은 `Workflow` 클래스에 대한 선택적 생성자 인수입니다.


| 인수 이름 | Type | 설명 | 
| --- | --- | --- | 
| Description | str | [워크플루 구조](aws-glue-api-workflow.md#aws-glue-api-workflow-Workflow)을(를) 참조하세요. | 
| DefaultRunProperties | dict | [워크플루 구조](aws-glue-api-workflow.md#aws-glue-api-workflow-Workflow)을(를) 참조하세요. | 
| OnSchedule | str | cron 표현식입니다. | 

## 클래스 메서드
<a name="developing-blueprints-code-methods"></a>

세 클래스 모두 다음 메서드를 포함합니다.

**validate()**  
객체의 속성을 검증하고 오류가 발견되면 메시지를 출력하고 종료합니다. 오류가 없으면 출력을 생성하지 않습니다. `Workflow` 클래스의 경우 워크플로의 모든 엔터티에서 자신을 호출합니다.

**to\$1json()**  
객체를 JSON으로 직렬화합니다. 또한 `validate()`를 호출합니다. `Workflow` 클래스의 경우 JSON 객체에는 작업 및 크롤러 목록과 작업 및 크롤러 종속성 사양에 의해 생성된 트리거 목록이 포함됩니다.

# 블루프린트 샘플
<a name="developing-blueprints-samples"></a>

[AWS Glue 블루프린트 Github 리포지토리](https://github.com/awslabs/aws-glue-blueprint-libs/tree/master/samples)에서 사용할 수 있는 샘플 블루프린트 프로젝트가 많이 있습니다. 이 샘플은 참조용이며 프로덕션 용도로 사용되지 않습니다.

샘플 프로젝트의 제목은 다음과 같습니다.
+ 압축: 이 블루프린트는 원하는 파일 크기에 따라 입력 파일을 더 큰 청크로 압축하는 작업을 생성합니다.
+ 변환: 이 블루프린트은 다양한 표준 파일 포맷의 입력 파일을 분석 워크로드에 최적화된 Apache Parkore 포맷으로 변환합니다.
+ Amazon S3 위치 크롤링: 이 블루프린트는 여러 Amazon S3 위치를 크롤링하여 Data Catalog에 메타데이터 테이블을 추가합니다.
+ Data Catalog에 대한 사용자 지정 연결: 이 블루프린트는 AWS Glue 사용자 지정 커넥터를 사용하여 데이터 스토어에 액세스하고, 레코드를 읽고, 레코드 스키마를 기준으로 AWS Glue Data Catalog에 테이블 정의를 채웁니다.
+ 인코딩: 이 블루프린트은 UTF가 아닌 파일을 UTF로 인코딩된 파일로 변환합니다.
+ 분할: 이 블루프린트는 특정 파티션 키를 기반으로 출력 파일을 파티션에 배치하는 분할 작업을 생성합니다.
+ Amazon S3 데이터를 DynamoDB 테이블로 가져오기: 이 블루프린트는 Amazon S3에서 DynamoDB 테이블로 데이터를 가져옵니다.
+ 관리 대상 표준 테이블: 이 블루프린트는 AWS Glue Data Catalog 테이블을 Lake Formation 테이블로 가져옵니다.