

# Asana에 연결
<a name="connecting-to-asana"></a>

Asana는 팀이 작업과 프로젝트를 구성, 계획, 완료할 수 있도록 지원하는 클라우드 기반 팀 협업 솔루션입니다. Asana 사용자인 경우 계정에는 워크스페이스, 프로젝트, 작업, 팀 등에 대한 데이터가 포함됩니다. Asana에서 특정 AWS 서비스 또는 기타 지원되는 애플리케이션으로 데이터를 전송할 수 있습니다.

**Topics**
+ [AWS Glue의 Asana 지원](asana-support.md)
+ [연결을 생성하고 사용하기 위한 API 작업이 포함된 정책](asana-configuring-iam-permissions.md)
+ [Asana 구성](asana-configuring.md)
+ [Asana 연결 구성](asana-configuring-connections.md)
+ [Asana 엔터티에서 읽기](asana-reading-from-entities.md)
+ [Asana 연결 옵션](asana-connection-options.md)
+ [Asana 계정 생성](asana-create-account.md)
+ [제한 사항](asana-connector-limitations.md)

# AWS Glue의 Asana 지원
<a name="asana-support"></a>

AWS Glue에서는 다음과 같이 Asana을 지원합니다.

**소스로 지원되나요?**  
예. AWS Glue ETL 작업을 사용하여 Asana에서 데이터를 쿼리할 수 있습니다.

**대상으로서 지원되나요?**  
아니요.

**지원되는 Asana API 버전**  
 1.0 

# 연결을 생성하고 사용하기 위한 API 작업이 포함된 정책
<a name="asana-configuring-iam-permissions"></a>

다음 샘플 정책에서는 연결을 생성하고 사용하는 데 필요한 AWS 권한을 설명합니다. 새 역할을 생성하는 경우 다음을 포함하는 정책을 생성합니다.

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

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "glue:ListConnectionTypes",
        "glue:DescribeConnectionType",
        "glue:RefreshOAuth2Tokens",
        "glue:ListEntities",
        "glue:DescribeEntity"
      ],
      "Resource": "*"
    }
  ]
}
```

------

이전 메서드를 사용하지 않으려는 경우 대신 다음 관리형 IAM 정책을 사용합니다.
+  [AWSGlueServiceRole](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/service-role/AWSGlueServiceRole) – 다양한 AWS Glue 프로세스를 대신 실행하는 데 필요한 리소스에 대한 액세스 권한을 부여합니다. 이러한 리소스에는 AWS Glue, Amazon S3, IAM, CloudWatch Logs 및 Amazon EC2가 포함됩니다. 이 정책에 지정된 리소스의 이름 변환을 따르고자 한다면 AWS Glue 절차는 필요한 권한을 소유합니다. 이 정책은 크롤러, 작업 및 개발 엔드포인트를 정의할 때 지정된 역할에 일반적으로 추가됩니다.
+  [AWSGlueConsoleFullAccess](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/AWSGlueConsoleFullAccess) - 정책이 연결된 자격 증명이 AWS Management 콘솔을 사용하는 경우 AWS Glue 리소스에 대한 전체 액세스 권한을 부여합니다. 이 정책에 지정된 리소스의 이름 변환을 따르면 사용자는 콘솔 전체 용량을 소유합니다. 이 정책은 보통 AWS Glue 콘솔의 사용자에게 해당됩니다.

# Asana 구성
<a name="asana-configuring"></a>

AWS Glue를 사용하여 Asana에서 데이터를 전송하려면 먼저 다음 요구 사항을 충족해야 합니다.

## 최소 요구 사항
<a name="asana-configuring-min-requirements"></a>
+ 이메일과 암호가 있는 Asana 계정이 있습니다. 계정 생성에 대한 자세한 내용은 [Asana 계정 생성](asana-create-account.md)을 참조하세요.
+ AWS Glue에 대한 서비스 액세스 권한으로 AWS 계정을 생성해야 합니다.
+ Asana 계정에서 다음 리소스 중 하나를 생성했는지 확인합니다.
  + `OAuth 2.0` 인증을 지원하는 개발자 앱. 자세한 지침은 Asana 개발자 설명서의 [OAuth](https://developers.asana.com/docs/oauth)를 참조하세요. 또는 [Asana 계정 생성](asana-create-account.md) 섹션을 참조하세요.
  + 개인 액세스 토큰입니다. 자세한 내용은 Asana 개발자 설명서의 개인 액세스 토큰[https://developers.asana.com/docs/personal-access-token](https://developers.asana.com/docs/personal-access-token)을 참조하세요.

이러한 요구 사항을 충족하면 Adobe Analytics 계정에 AWS Glue를 연결할 준비가 된 것입니다. 일반적인 연결의 경우 Adobe Analytics에서 다른 작업을 수행하지 않아도 됩니다.

# Asana 연결 구성
<a name="asana-configuring-connections"></a>

Asana는 `OAuth2`에 대한 `AUTHORIZATION_CODE` 권한 부여 유형을 지원합니다.

이 권한 부여 유형은 사용자를 인증하기 위해 사용자를 서드파티 권한 부여 서버로 리디렉션하는 방식에 의존하므로 '3각' `OAuth`로 간주됩니다. 사용자는 AWS Glue 콘솔을 통해 연결을 생성할 때에도 Asana에서 자체 연결된 앱을 생성하고 자체 클라이언트 ID와 클라이언트 보안 암호를 제공하기로 선택할 수 있습니다. 이 시나리오에서는 여전히 Asana로 리디렉션되어 로그인하고 리소스에 액세스할 수 있는 권한을 AWS Glue에 부여합니다.

이 권한 부여 유형은 새로 고침 토큰과 액세스 토큰을 생성합니다. 액세스 토큰은 수명이 짧으며 새로 고침 토큰을 사용하여 사용자 상호 작용 없이 자동으로 새로 고칠 수 있습니다.

`AUTHORIZATION_CODE OAuth` 흐름을 위해 연결된 앱을 생성하는 방법에 대한 퍼블릭 Asana 설명서는 [Asana API](https://developers.asana.com/docs/oauth)를 참조하세요.

Asana 연결을 구성하는 방법:

1. AWS Secrets Manager에서 다음 세부 정보로 보안 암호를 생성합니다.
   + 고객 관리형 연결된 앱의 경우 - 보안 암호는 키 역할을 하는 `USER_MANAGED_CLIENT_APPLICATION_CLIENT_SECRET`과 함께 연결된 앱 소비자 보안 암호를 포함해야 합니다.
   + 
**참고**  
AWS Glue에서 연결에 대한 보안 암호를 생성해야 합니다.

1. AWS Glue Studio의 **데이터 연결**에서 아래 단계에 따라 연결을 생성합니다.

   1. **연결 유형**을 선택할 때 Asana을 선택합니다.

   1. Asana 환경을 제공합니다.

   1. 다음 작업에 대한 권한이 있고 AWS Glue에서 수임할 수 있는 IAM 역할을 선택합니다.

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

****  

      ```
      {
        "Version":"2012-10-17",		 	 	 
        "Statement": [
          {
            "Effect": "Allow",
            "Action": [
              "secretsmanager:DescribeSecret",
              "secretsmanager:GetSecretValue",
              "secretsmanager:PutSecretValue",
              "ec2:CreateNetworkInterface",
              "ec2:DescribeNetworkInterfaces",
              "ec2:DeleteNetworkInterface"
            ],
            "Resource": "*"
          }
        ]
      }
      ```

------

   1. 토큰을 넣기 위해 AWS Glue에서 이 연결에 사용할 `secretName`을 선택합니다.

   1.  네트워크를 사용하려는 경우 네트워크 옵션을 선택합니다.

1. AWS Glue 작업 권한과 연결된 IAM 역할에 `secretName`을 읽을 수 있는 권한을 부여합니다.

# Asana 엔터티에서 읽기
<a name="asana-reading-from-entities"></a>

 **사전 조건** 

읽으려는 Asana 객체입니다. 사용 가능한 엔터티를 확인하려면 아래 지원되는 엔터티 테이블을 참조하세요.

 **소스에 대해 지원되는 엔터티** 


| 개체 | 필터링 가능 | 제한 지원 | 정렬 기준 지원 | Select \$1 지원 | 분할 지원 | 
| --- | --- | --- | --- | --- | --- | 
|  워크스페이스  | 아니요 | 예 | 아니요 | 예 | 아니요 | 
| 태그 | 아니요 | 예 | 아니요 | 예 | 아니요 | 
| User | 아니요 | 예 | 아니요 | 예 | 아니요 | 
|  Portfolio  | 아니요 | 예 | 아니요 | 예 | 아니요 | 
| Team | 아니요 | 예 | 아니요 | 예 | 아니요 | 
| Project | 예 | 예 | 아니요 | 예 | 아니요 | 
| Section | 아니요 | 예 | 아니요 | 예 | 아니요 | 
| Task  | 예 | 아니요 | 아니요 | 예 | 예 | 
| Goal | 예 | 예 | 아니요 | 예 | 아니요 | 
|  AuditLogEvent  | 예 | 예 | 아니요 | 예 | 아니요 | 
|  Status Update  | 예 | 예 | 아니요 | 예 | 아니요 | 
|  Custom Field  | 아니요 | 예 | 아니요 | 예 | 아니요 | 
|  Project Brief  | 예 | 아니요 | 아니요 | 예 | 예 | 

 **예제** 

```
read_read = glueContext.create_dynamic_frame.from_options(
    connection_type="Asana",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "task/workspace:xxxx",
        "API_VERSION": "1.0",
        "PARTITION_FIELD": "created_at",
        "LOWER_BOUND": "2024-02-05T14:09:30.115Z",
        "UPPER_BOUND": "2024-06-07T13:30:00.134Z",
        "NUM_PARTITIONS": "3"
    }
```

 **Asana 엔터티 및 필드 세부 정보** 
+ [Workspace](https://developers.asana.com/docs/workspaces)
+ [태그](https://developers.asana.com/docs/tags)
+ [User](https://developers.asana.com/docs/users)
+ [Portfolio](https://developers.asana.com/docs/portfolios)
+ [Team](https://developers.asana.com/docs/teams)
+ [Project](https://developers.asana.com/docs/get-all-projects-in-a-workspace)
+ [Section](https://developers.asana.com/docs/get-sections-in-a-project)
+ [Task](https://developers.asana.com/docs/search-tasks-in-a-workspace) 
+ [Goal](https://developers.asana.com/docs/get-goals)
+ [AuditLogEvent](https://developers.asana.com/docs/audit-log-api)
+ [Status Update](https://developers.asana.com/reference/status-updates)
+ [Custom Field](https://developers.asana.com/reference/custom-fields)
+ [Project Brief](https://developers.asana.com/reference/project-briefs)

 **분할 쿼리** 

Spark에서 동시성을 활용하려는 경우 추가 Spark 옵션(`PARTITION_FIELD`, `LOWER_BOUND`, `UPPER_BOUND`, `NUM_PARTITIONS`)을 제공할 수 있습니다. 이러한 파라미터를 사용하면 Spark 태스크에서 동시에 실행할 수 있는 `NUM_PARTITIONS`개의 하위 쿼리로 원본 쿼리가 분할됩니다.
+ `PARTITION_FIELD`: 쿼리 분할에 사용할 필드의 이름입니다.
+ `LOWER_BOUND`: 선택한 파티션 필드의 하한 값(경계 포함).

  날짜의 경우 Spark SQL 쿼리에 사용된 Spark 날짜 형식을 허용합니다. 유효한 값의 예제: `2024-06-07T13:30:00.134Z`.
+ `UPPER_BOUND`: 선택한 파티션 필드의 상한 값(경계 제외).
+ `NUM_PARTITIONS`: 파티션 수.

 엔터티 수준의 분할 필드 지원 세부 정보는 다음 표에 캡처되어 있습니다.


| 엔터티 이름 | 분할 필드 | 데이터 형식 | 
| --- | --- | --- | 
| Task |  created\$1at  | DateTime | 
| Task |  modified\$1at  | DateTime | 

 **예제** 

```
read_read = glueContext.create_dynamic_frame.from_options(
    connection_type="Asana",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "task/workspace:xxxx",
        "API_VERSION": "1.0",
        "PARTITION_FIELD": "created_at",
        "LOWER_BOUND": "2024-02-05T14:09:30.115Z",
        "UPPER_BOUND": "2024-06-07T13:30:00.134Z",
        "NUM_PARTITIONS": "3"
    }
```

# Asana 연결 옵션
<a name="asana-connection-options"></a>

다음은 Asana의 연결 옵션입니다.
+  `ENTITY_NAME`(문자열) - (필수) 읽기/쓰기에 사용됩니다. Asana에서의 객체 이름입니다.
+  `API_VERSION`(문자열) - (필수) 읽기/쓰기에 사용됩니다. 사용할 Asana Rest API 버전입니다. 예: 1.0.
+  `SELECTED_FIELDS`(List<String>) - 기본값: 비어 있습니다(SELECT \$1). 읽기에 사용됩니다. 객체에 대해 선택할 열.
+  `FILTER_PREDICATE`(문자열) - 기본값: 비어 있습니다. 읽기에 사용됩니다. Spark SQL 형식이어야 합니다.
+  `QUERY`(문자열) - 기본값: 비어 있습니다. 읽기에 사용됩니다. 전체 Spark SQL 쿼리.
+ `PARTITION_FIELD`(문자열) - 읽기에 사용됩니다. 쿼리 분할에 사용할 필드입니다.
+  `LOWER_BOUND`(문자열) - 읽기에 사용됩니다. 선택한 파티션 필드의 하한 값(경계 포함).
+  `UPPER_BOUND`(문자열) - 읽기에 사용됩니다. 선택한 파티션 필드의 상한 값(경계 제외).
+  `NUM_PARTITIONS`(정수) - 기본값: 1. 읽기에 사용됩니다. 읽을 파티션 수.

# Asana 계정 생성
<a name="asana-create-account"></a>

1. [Asana 계정](https://asana.com/create-account)에 가입하고 **가입**을 선택합니다.

1. 로그인하면 [계정 설정](https://app.asana.com/0/account_setup) 페이지로 리디렉션됩니다. 다음 단계를 완료합니다.
   + 계정 설정 양식을 검토합니다.
   + 관련 세부 정보를 모두 입력하여 Asana 계정을 생성합니다.
   + 정보가 정확한지 다시 확인합니다.

1. **계정 생성** 또는 **제출**(정확한 버튼 텍스트는 다를 수 있음)을 선택하여 계정 설정을 완료합니다.

**`OAuth2.0`용 Asana에서 앱 생성**

1. [Asana 고객 자격 증명](https://app.asana.com/-/login)을 사용하여 Asana 계정에 로그인합니다.

1. 오른쪽 상단 모서리에서 사용자 프로필 아이콘을 선택하고 드롭다운 메뉴에서 **내 설정**을 선택합니다.

1. **앱** 탭을 선택한 다음 **개발자 앱 관리**를 선택합니다.

1. **새 앱 생성**을 선택하고 관련 세부 정보를 입력합니다.

1. **앱 생성**을 선택합니다.

1. **내 앱** 페이지에서: 

   1. **OAuth**를 선택하고 **앱 자격 증명** 섹션에서 클라이언트 ID와 클라이언트 보안 암호를 기록해 둡니다.

   1. **리디렉션 URL** 섹션에서 필요한 리디렉션 URL을 추가합니다.
**참고**  
`https://{aws-region-code}.console.aws.amazon.com/gluestudio/oauth`의 이 형식을 사용하여 리디렉션 URI를 입력합니다. 예시: 미국 동부(버지니아 북부)의 경우 `https://us-east-1.console.aws.amazon.com/gluestudio/oauth`를 사용합니다.

**`PAT` 토큰용 Asana에서 앱 생성**

1. [Asana 고객 자격 증명](https://app.asana.com/-/login)을 사용하여 Asana 계정에 로그인합니다.

1. 오른쪽 상단 모서리의 사용자 프로필 아이콘에서 선택하고 드롭다운 메뉴에서 **내 프로필 설정**을 선택합니다.

1. **앱** 탭을 선택한 다음 **서비스 계정**을 선택합니다.

1. **새 앱 생성**을 선택하고 관련 세부 정보를 입력합니다.

1. **서비스 계정 추가**를 선택하세요.

1. 다음 페이지에 토큰이 표시되고 토큰을 복사하여 안전하게 저장합니다.
**중요**  
이 토큰은 한 번만 표시됩니다. 복사하여 안전하게 저장해야 합니다.

# 제한 사항
<a name="asana-connector-limitations"></a>

다음은 Asana 커넥터의 제한 사항입니다.
+ 엔터프라이즈 도메인의 서비스 계정은 감사 로그 API 엔드포인트에만 액세스할 수 있습니다. 이러한 엔드포인트에 액세스하려면 서비스 계정의 개인 액세스 토큰으로 인증해야 합니다.
+ Goal 엔터티는 프리미엄 요금제 이상이 있는 사용자 계정에서만 액세스할 수 있습니다.
+ `Audit Log Event Entity` - 커넥터에서 `start_at` 및 `end_at` 필드는 필터링 및 증분 전송을 지원하기 위해 단일 필드 "start\$1end\$1at"로 결합됩니다.
+ `Date` 필드가 greater-than-or-equal-to 연산자와 less-than-or-equal-to 연산자를 지원하더라도 분할은 지원되지 않습니다. 시나리오: `partitionField`를 `due_on`(데이터 유형: 날짜)으로, `lowerBound`를 `2019-09-14`로, `upperBound`를 `2019-09-16`으로, `numPartition`을 `2`로 작업을 생성했습니다. 엔드포인트 URL의 필터 부분은 다음과 같이 생성됩니다.
  + partition1: due\$1on.before=2019-09-14&due\$1on.after=2019-09-14
  + partition2: due\$1on.before=2019-09-15&due\$1on.after=2019-09-15 Output:
  + partition1에서는 due\$1date가 2019-09-14 및 2019-09-15인 데이터를 가져옵니다.
  + partition2에서는 다른 데이터와 함께 due\$1date가 2019-09-15(partition1에서 가져온 데이터)인 동일한 데이터를 가져와 데이터 중복을 일으킵니다.
+ SaaS 끝에서 잘못된 요청 오류가 발생하므로 동일한 필드에서 필터링 및 분할을 지원할 수 없습니다.
+ 작업 엔터티에는 필터 기준에 최소 1개의 필드가 필요합니다. Asana에는 시간 기반 필드를 기반으로 레코드를 정렬하지 않고서는 페이지 매김이 식별되지 않는 제한이 있습니다. 따라서 Created\$1at 필드는 페이지 매김과 함께 다음 레코드 세트를 구분하는 데 사용됩니다. Created\$1at 필드는 필터에서 필수로 표시되며, 제공되지 않은 경우 기본값은 2000-01-01T00:00:00Z입니다. 페이지 매김에 대한 자세한 내용은 [작업 영역의 작업](https://developers.asana.com/reference/searchtasksforworkspace)을 참조하세요.