embulk-output-s3_parquet 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +3 -0
- data/.github/workflows/test.yml +2 -0
- data/.scalafmt.conf +5 -0
- data/CHANGELOG.md +15 -0
- data/README.md +3 -2
- data/build.gradle +19 -9
- data/example/config.yml +3 -1
- data/example/prepare_s3_bucket.sh +6 -0
- data/example/with_catalog.yml +3 -1
- data/example/with_logicaltypes.yml +3 -1
- data/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/gradle/wrapper/gradle-wrapper.properties +1 -1
- data/gradlew +31 -20
- data/gradlew.bat +17 -1
- data/run_s3_local.sh +7 -0
- data/src/main/scala/org/embulk/output/s3_parquet/CatalogRegistrator.scala +226 -178
- data/src/main/scala/org/embulk/output/s3_parquet/ContextClassLoaderSwapper.scala +18 -0
- data/src/main/scala/org/embulk/output/s3_parquet/S3ParquetOutputPlugin.scala +293 -204
- data/src/main/scala/org/embulk/output/s3_parquet/S3ParquetPageOutput.scala +46 -49
- data/src/main/scala/org/embulk/output/s3_parquet/aws/Aws.scala +46 -50
- data/src/main/scala/org/embulk/output/s3_parquet/aws/AwsClientConfiguration.scala +18 -23
- data/src/main/scala/org/embulk/output/s3_parquet/aws/AwsCredentials.scala +146 -119
- data/src/main/scala/org/embulk/output/s3_parquet/aws/AwsEndpointConfiguration.scala +32 -35
- data/src/main/scala/org/embulk/output/s3_parquet/aws/AwsS3Configuration.scala +45 -41
- data/src/main/scala/org/embulk/output/s3_parquet/aws/HttpProxy.scala +40 -43
- data/src/main/scala/org/embulk/output/s3_parquet/parquet/EmbulkMessageType.scala +138 -92
- data/src/main/scala/org/embulk/output/s3_parquet/parquet/LogicalTypeHandler.scala +117 -102
- data/src/main/scala/org/embulk/output/s3_parquet/parquet/LogicalTypeHandlerStore.scala +91 -84
- data/src/main/scala/org/embulk/output/s3_parquet/parquet/ParquetFileWriteSupport.scala +30 -29
- data/src/main/scala/org/embulk/output/s3_parquet/parquet/ParquetFileWriter.scala +143 -152
- data/src/test/scala/org/embulk/output/s3_parquet/TestS3ParquetOutputPlugin.scala +144 -117
- data/src/test/scala/org/embulk/output/s3_parquet/parquet/TestLogicalTypeHandler.scala +72 -66
- data/src/test/scala/org/embulk/output/s3_parquet/parquet/TestLogicalTypeHandlerStore.scala +149 -132
- metadata +22 -15
@@ -1,6 +1,5 @@
|
|
1
1
|
package org.embulk.output.s3_parquet
|
2
2
|
|
3
|
-
|
4
3
|
import java.io.File
|
5
4
|
import java.nio.file.{Files, Paths}
|
6
5
|
|
@@ -11,63 +10,61 @@ import org.embulk.config.TaskReport
|
|
11
10
|
import org.embulk.output.s3_parquet.aws.Aws
|
12
11
|
import org.embulk.spi.{Exec, Page, PageReader, TransactionalPageOutput}
|
13
12
|
|
13
|
+
case class S3ParquetPageOutput(
|
14
|
+
outputLocalFile: String,
|
15
|
+
reader: PageReader,
|
16
|
+
writer: ParquetWriter[PageReader],
|
17
|
+
aws: Aws,
|
18
|
+
destBucket: String,
|
19
|
+
destKey: String
|
20
|
+
) extends TransactionalPageOutput {
|
14
21
|
|
15
|
-
|
16
|
-
reader: PageReader,
|
17
|
-
writer: ParquetWriter[PageReader],
|
18
|
-
aws: Aws,
|
19
|
-
destBucket: String,
|
20
|
-
destKey: String)
|
21
|
-
extends TransactionalPageOutput
|
22
|
-
{
|
23
|
-
|
24
|
-
private var isClosed: Boolean = false
|
22
|
+
private var isClosed: Boolean = false
|
25
23
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
writer.write(reader)
|
31
|
-
}
|
24
|
+
override def add(page: Page): Unit = {
|
25
|
+
reader.setPage(page)
|
26
|
+
while (reader.nextRecord()) {
|
27
|
+
writer.write(reader)
|
32
28
|
}
|
29
|
+
}
|
33
30
|
|
34
|
-
|
35
|
-
{
|
36
|
-
}
|
31
|
+
override def finish(): Unit = {}
|
37
32
|
|
38
|
-
|
39
|
-
{
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
isClosed = true
|
44
|
-
}
|
33
|
+
override def close(): Unit = {
|
34
|
+
synchronized {
|
35
|
+
if (!isClosed) {
|
36
|
+
ContextClassLoaderSwapper.usingPluginClass {
|
37
|
+
writer.close()
|
45
38
|
}
|
39
|
+
isClosed = true
|
40
|
+
}
|
46
41
|
}
|
42
|
+
}
|
47
43
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
}
|
44
|
+
override def abort(): Unit = {
|
45
|
+
close()
|
46
|
+
cleanup()
|
47
|
+
}
|
53
48
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
Exec.newTaskReport()
|
63
|
-
.set("bucket", result.getBucketName)
|
64
|
-
.set("key", result.getKey)
|
65
|
-
.set("etag", result.getETag)
|
66
|
-
.set("version_id", result.getVersionId)
|
49
|
+
override def commit(): TaskReport = {
|
50
|
+
close()
|
51
|
+
val result: UploadResult = ContextClassLoaderSwapper.usingPluginClass {
|
52
|
+
aws.withTransferManager { xfer: TransferManager =>
|
53
|
+
val upload: Upload =
|
54
|
+
xfer.upload(destBucket, destKey, new File(outputLocalFile))
|
55
|
+
upload.waitForUploadResult()
|
56
|
+
}
|
67
57
|
}
|
58
|
+
cleanup()
|
59
|
+
Exec
|
60
|
+
.newTaskReport()
|
61
|
+
.set("bucket", result.getBucketName)
|
62
|
+
.set("key", result.getKey)
|
63
|
+
.set("etag", result.getETag)
|
64
|
+
.set("version_id", result.getVersionId)
|
65
|
+
}
|
68
66
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
}
|
67
|
+
private def cleanup(): Unit = {
|
68
|
+
Files.delete(Paths.get(outputLocalFile))
|
69
|
+
}
|
73
70
|
}
|
@@ -1,63 +1,59 @@
|
|
1
1
|
package org.embulk.output.s3_parquet.aws
|
2
2
|
|
3
|
-
|
4
3
|
import com.amazonaws.client.builder.AwsClientBuilder
|
5
4
|
import com.amazonaws.services.glue.{AWSGlue, AWSGlueClientBuilder}
|
6
5
|
import com.amazonaws.services.s3.{AmazonS3, AmazonS3ClientBuilder}
|
7
|
-
import com.amazonaws.services.s3.transfer.{
|
8
|
-
|
9
|
-
|
10
|
-
object Aws
|
11
|
-
{
|
12
|
-
|
13
|
-
trait Task
|
14
|
-
extends AwsCredentials.Task
|
15
|
-
with AwsEndpointConfiguration.Task
|
16
|
-
with AwsClientConfiguration.Task
|
17
|
-
with AwsS3Configuration.Task
|
18
|
-
|
19
|
-
def apply(task: Task): Aws =
|
20
|
-
{
|
21
|
-
new Aws(task)
|
22
|
-
}
|
23
|
-
|
6
|
+
import com.amazonaws.services.s3.transfer.{
|
7
|
+
TransferManager,
|
8
|
+
TransferManagerBuilder
|
24
9
|
}
|
25
10
|
|
26
|
-
|
27
|
-
{
|
28
|
-
|
29
|
-
def withS3[A](f: AmazonS3 => A): A =
|
30
|
-
{
|
31
|
-
val builder: AmazonS3ClientBuilder = AmazonS3ClientBuilder.standard()
|
32
|
-
AwsS3Configuration(task).configureAmazonS3ClientBuilder(builder)
|
33
|
-
val svc = createService(builder)
|
34
|
-
try f(svc)
|
35
|
-
finally svc.shutdown()
|
36
|
-
}
|
11
|
+
object Aws {
|
37
12
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
finally svc.shutdownNow(false)
|
44
|
-
}
|
45
|
-
}
|
13
|
+
trait Task
|
14
|
+
extends AwsCredentials.Task
|
15
|
+
with AwsEndpointConfiguration.Task
|
16
|
+
with AwsClientConfiguration.Task
|
17
|
+
with AwsS3Configuration.Task
|
46
18
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
val svc = createService(builder)
|
51
|
-
try f(svc)
|
52
|
-
finally svc.shutdown()
|
53
|
-
}
|
19
|
+
def apply(task: Task): Aws = {
|
20
|
+
new Aws(task)
|
21
|
+
}
|
54
22
|
|
55
|
-
|
56
|
-
{
|
57
|
-
AwsEndpointConfiguration(task).configureAwsClientBuilder(builder)
|
58
|
-
AwsClientConfiguration(task).configureAwsClientBuilder(builder)
|
59
|
-
builder.setCredentials(AwsCredentials(task).createAwsCredentialsProvider)
|
23
|
+
}
|
60
24
|
|
61
|
-
|
25
|
+
class Aws(task: Aws.Task) {
|
26
|
+
|
27
|
+
def withS3[A](f: AmazonS3 => A): A = {
|
28
|
+
val builder: AmazonS3ClientBuilder = AmazonS3ClientBuilder.standard()
|
29
|
+
AwsS3Configuration(task).configureAmazonS3ClientBuilder(builder)
|
30
|
+
val svc = createService(builder)
|
31
|
+
try f(svc)
|
32
|
+
finally svc.shutdown()
|
33
|
+
}
|
34
|
+
|
35
|
+
def withTransferManager[A](f: TransferManager => A): A = {
|
36
|
+
withS3 { s3 =>
|
37
|
+
val svc = TransferManagerBuilder.standard().withS3Client(s3).build()
|
38
|
+
try f(svc)
|
39
|
+
finally svc.shutdownNow(false)
|
62
40
|
}
|
41
|
+
}
|
42
|
+
|
43
|
+
def withGlue[A](f: AWSGlue => A): A = {
|
44
|
+
val builder: AWSGlueClientBuilder = AWSGlueClientBuilder.standard()
|
45
|
+
val svc = createService(builder)
|
46
|
+
try f(svc)
|
47
|
+
finally svc.shutdown()
|
48
|
+
}
|
49
|
+
|
50
|
+
def createService[S <: AwsClientBuilder[S, T], T](
|
51
|
+
builder: AwsClientBuilder[S, T]
|
52
|
+
): T = {
|
53
|
+
AwsEndpointConfiguration(task).configureAwsClientBuilder(builder)
|
54
|
+
AwsClientConfiguration(task).configureAwsClientBuilder(builder)
|
55
|
+
builder.setCredentials(AwsCredentials(task).createAwsCredentialsProvider)
|
56
|
+
|
57
|
+
builder.build()
|
58
|
+
}
|
63
59
|
}
|
@@ -1,6 +1,5 @@
|
|
1
1
|
package org.embulk.output.s3_parquet.aws
|
2
2
|
|
3
|
-
|
4
3
|
import java.util.Optional
|
5
4
|
|
6
5
|
import com.amazonaws.ClientConfiguration
|
@@ -8,35 +7,31 @@ import com.amazonaws.client.builder.AwsClientBuilder
|
|
8
7
|
import org.embulk.config.{Config, ConfigDefault}
|
9
8
|
import org.embulk.output.s3_parquet.aws.AwsClientConfiguration.Task
|
10
9
|
|
10
|
+
object AwsClientConfiguration {
|
11
11
|
|
12
|
-
|
13
|
-
{
|
14
|
-
|
15
|
-
trait Task
|
16
|
-
{
|
12
|
+
trait Task {
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
@Config("http_proxy")
|
15
|
+
@ConfigDefault("null")
|
16
|
+
def getHttpProxy: Optional[HttpProxy.Task]
|
21
17
|
|
22
|
-
|
18
|
+
}
|
23
19
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
}
|
20
|
+
def apply(task: Task): AwsClientConfiguration = {
|
21
|
+
new AwsClientConfiguration(task)
|
22
|
+
}
|
28
23
|
}
|
29
24
|
|
30
|
-
class AwsClientConfiguration(task: Task)
|
31
|
-
{
|
25
|
+
class AwsClientConfiguration(task: Task) {
|
32
26
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
27
|
+
def configureAwsClientBuilder[S <: AwsClientBuilder[S, T], T](
|
28
|
+
builder: AwsClientBuilder[S, T]
|
29
|
+
): Unit = {
|
30
|
+
task.getHttpProxy.ifPresent { v =>
|
31
|
+
val cc = new ClientConfiguration
|
32
|
+
HttpProxy(v).configureClientConfiguration(cc)
|
33
|
+
builder.setClientConfiguration(cc)
|
40
34
|
}
|
35
|
+
}
|
41
36
|
|
42
37
|
}
|
@@ -1,147 +1,174 @@
|
|
1
1
|
package org.embulk.output.s3_parquet.aws
|
2
2
|
|
3
|
-
|
4
3
|
import java.util.Optional
|
5
4
|
|
6
|
-
import com.amazonaws.auth.{
|
7
|
-
|
5
|
+
import com.amazonaws.auth.{
|
6
|
+
AnonymousAWSCredentials,
|
7
|
+
AWSCredentialsProvider,
|
8
|
+
AWSStaticCredentialsProvider,
|
9
|
+
BasicAWSCredentials,
|
10
|
+
BasicSessionCredentials,
|
11
|
+
DefaultAWSCredentialsProviderChain,
|
12
|
+
EC2ContainerCredentialsProviderWrapper,
|
13
|
+
EnvironmentVariableCredentialsProvider,
|
14
|
+
STSAssumeRoleSessionCredentialsProvider,
|
15
|
+
SystemPropertiesCredentialsProvider,
|
16
|
+
WebIdentityTokenCredentialsProvider
|
17
|
+
}
|
18
|
+
import com.amazonaws.auth.profile.{
|
19
|
+
ProfileCredentialsProvider,
|
20
|
+
ProfilesConfigFile
|
21
|
+
}
|
8
22
|
import org.embulk.config.{Config, ConfigDefault, ConfigException}
|
9
23
|
import org.embulk.output.s3_parquet.aws.AwsCredentials.Task
|
10
24
|
import org.embulk.spi.unit.LocalFile
|
11
25
|
|
26
|
+
object AwsCredentials {
|
12
27
|
|
13
|
-
|
14
|
-
{
|
28
|
+
trait Task {
|
15
29
|
|
16
|
-
|
17
|
-
|
30
|
+
@Config("auth_method")
|
31
|
+
@ConfigDefault("\"default\"")
|
32
|
+
def getAuthMethod: String
|
18
33
|
|
19
|
-
|
20
|
-
|
21
|
-
|
34
|
+
@Config("access_key_id")
|
35
|
+
@ConfigDefault("null")
|
36
|
+
def getAccessKeyId: Optional[String]
|
22
37
|
|
23
|
-
|
24
|
-
|
25
|
-
|
38
|
+
@Config("secret_access_key")
|
39
|
+
@ConfigDefault("null")
|
40
|
+
def getSecretAccessKey: Optional[String]
|
26
41
|
|
27
|
-
|
28
|
-
|
29
|
-
|
42
|
+
@Config("session_token")
|
43
|
+
@ConfigDefault("null")
|
44
|
+
def getSessionToken: Optional[String]
|
30
45
|
|
31
|
-
|
32
|
-
|
33
|
-
|
46
|
+
@Config("profile_file")
|
47
|
+
@ConfigDefault("null")
|
48
|
+
def getProfileFile: Optional[LocalFile]
|
34
49
|
|
35
|
-
|
36
|
-
|
37
|
-
|
50
|
+
@Config("profile_name")
|
51
|
+
@ConfigDefault("\"default\"")
|
52
|
+
def getProfileName: String
|
38
53
|
|
39
|
-
|
40
|
-
|
41
|
-
|
54
|
+
@Config("role_arn")
|
55
|
+
@ConfigDefault("null")
|
56
|
+
def getRoleArn: Optional[String]
|
42
57
|
|
43
|
-
|
44
|
-
|
45
|
-
|
58
|
+
@Config("role_session_name")
|
59
|
+
@ConfigDefault("null")
|
60
|
+
def getRoleSessionName: Optional[String]
|
46
61
|
|
47
|
-
|
48
|
-
|
49
|
-
|
62
|
+
@Config("role_external_id")
|
63
|
+
@ConfigDefault("null")
|
64
|
+
def getRoleExternalId: Optional[String]
|
50
65
|
|
51
|
-
|
52
|
-
|
53
|
-
|
66
|
+
@Config("role_session_duration_seconds")
|
67
|
+
@ConfigDefault("null")
|
68
|
+
def getRoleSessionDurationSeconds: Optional[Int]
|
54
69
|
|
55
|
-
|
56
|
-
|
57
|
-
|
70
|
+
@Config("scope_down_policy")
|
71
|
+
@ConfigDefault("null")
|
72
|
+
def getScopeDownPolicy: Optional[String]
|
58
73
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
@Config("web_identity_token_file")
|
64
|
-
@ConfigDefault("null")
|
65
|
-
def getWebIdentityTokenFile: Optional[String]
|
66
|
-
}
|
74
|
+
@Config("web_identity_token_file")
|
75
|
+
@ConfigDefault("null")
|
76
|
+
def getWebIdentityTokenFile: Optional[String]
|
77
|
+
}
|
67
78
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
}
|
79
|
+
def apply(task: Task): AwsCredentials = {
|
80
|
+
new AwsCredentials(task)
|
81
|
+
}
|
72
82
|
}
|
73
83
|
|
74
|
-
class AwsCredentials(task: Task)
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
case "properties" =>
|
101
|
-
new SystemPropertiesCredentialsProvider
|
102
|
-
|
103
|
-
case "anonymous" =>
|
104
|
-
new AWSStaticCredentialsProvider(new AnonymousAWSCredentials)
|
105
|
-
|
106
|
-
case "session" =>
|
107
|
-
new AWSStaticCredentialsProvider(new BasicSessionCredentials(
|
108
|
-
getRequiredOption(task.getAccessKeyId, "access_key_id"),
|
109
|
-
getRequiredOption(task.getSecretAccessKey, "secret_access_key"),
|
110
|
-
getRequiredOption(task.getSessionToken, "session_token")
|
111
|
-
))
|
112
|
-
|
113
|
-
case "assume_role" =>
|
114
|
-
// NOTE: Are http_proxy, endpoint, region required when assuming role?
|
115
|
-
val builder = new STSAssumeRoleSessionCredentialsProvider.Builder(
|
116
|
-
getRequiredOption(task.getRoleArn, "role_arn"),
|
117
|
-
getRequiredOption(task.getRoleSessionName, "role_session_name")
|
118
|
-
)
|
119
|
-
task.getRoleExternalId.ifPresent(v => builder.withExternalId(v))
|
120
|
-
task.getRoleSessionDurationSeconds.ifPresent(v => builder.withRoleSessionDurationSeconds(v))
|
121
|
-
task.getScopeDownPolicy.ifPresent(v => builder.withScopeDownPolicy(v))
|
122
|
-
|
123
|
-
builder.build()
|
124
|
-
|
125
|
-
case "web_identity_token" =>
|
126
|
-
WebIdentityTokenCredentialsProvider.builder()
|
127
|
-
.roleArn(getRequiredOption(task.getRoleArn, "role_arn"))
|
128
|
-
.roleSessionName(getRequiredOption(task.getRoleSessionName, "role_session_name"))
|
129
|
-
.webIdentityTokenFile(getRequiredOption(task.getWebIdentityTokenFile, "web_identity_token_file"))
|
130
|
-
.build()
|
131
|
-
|
132
|
-
case "default" =>
|
133
|
-
new DefaultAWSCredentialsProviderChain
|
134
|
-
|
135
|
-
case am =>
|
136
|
-
throw new ConfigException(s"'$am' is unsupported: `auth_method` must be one of ['basic', 'env', 'instance', 'profile', 'properties', 'anonymous', 'session', 'assume_role', 'default'].")
|
84
|
+
class AwsCredentials(task: Task) {
|
85
|
+
|
86
|
+
def createAwsCredentialsProvider: AWSCredentialsProvider = {
|
87
|
+
task.getAuthMethod match {
|
88
|
+
case "basic" =>
|
89
|
+
new AWSStaticCredentialsProvider(
|
90
|
+
new BasicAWSCredentials(
|
91
|
+
getRequiredOption(task.getAccessKeyId, "access_key_id"),
|
92
|
+
getRequiredOption(task.getSecretAccessKey, "secret_access_key")
|
93
|
+
)
|
94
|
+
)
|
95
|
+
|
96
|
+
case "env" =>
|
97
|
+
new EnvironmentVariableCredentialsProvider
|
98
|
+
|
99
|
+
case "instance" =>
|
100
|
+
// NOTE: combination of InstanceProfileCredentialsProvider and ContainerCredentialsProvider
|
101
|
+
new EC2ContainerCredentialsProviderWrapper
|
102
|
+
|
103
|
+
case "profile" =>
|
104
|
+
if (task.getProfileFile.isPresent) {
|
105
|
+
val pf: ProfilesConfigFile = new ProfilesConfigFile(
|
106
|
+
task.getProfileFile.get().getFile
|
107
|
+
)
|
108
|
+
new ProfileCredentialsProvider(pf, task.getProfileName)
|
137
109
|
}
|
110
|
+
else new ProfileCredentialsProvider(task.getProfileName)
|
111
|
+
|
112
|
+
case "properties" =>
|
113
|
+
new SystemPropertiesCredentialsProvider
|
114
|
+
|
115
|
+
case "anonymous" =>
|
116
|
+
new AWSStaticCredentialsProvider(new AnonymousAWSCredentials)
|
117
|
+
|
118
|
+
case "session" =>
|
119
|
+
new AWSStaticCredentialsProvider(
|
120
|
+
new BasicSessionCredentials(
|
121
|
+
getRequiredOption(task.getAccessKeyId, "access_key_id"),
|
122
|
+
getRequiredOption(task.getSecretAccessKey, "secret_access_key"),
|
123
|
+
getRequiredOption(task.getSessionToken, "session_token")
|
124
|
+
)
|
125
|
+
)
|
126
|
+
|
127
|
+
case "assume_role" =>
|
128
|
+
// NOTE: Are http_proxy, endpoint, region required when assuming role?
|
129
|
+
val builder = new STSAssumeRoleSessionCredentialsProvider.Builder(
|
130
|
+
getRequiredOption(task.getRoleArn, "role_arn"),
|
131
|
+
getRequiredOption(task.getRoleSessionName, "role_session_name")
|
132
|
+
)
|
133
|
+
task.getRoleExternalId.ifPresent(v => builder.withExternalId(v))
|
134
|
+
task.getRoleSessionDurationSeconds.ifPresent(v =>
|
135
|
+
builder.withRoleSessionDurationSeconds(v)
|
136
|
+
)
|
137
|
+
task.getScopeDownPolicy.ifPresent(v => builder.withScopeDownPolicy(v))
|
138
|
+
|
139
|
+
builder.build()
|
140
|
+
|
141
|
+
case "web_identity_token" =>
|
142
|
+
WebIdentityTokenCredentialsProvider
|
143
|
+
.builder()
|
144
|
+
.roleArn(getRequiredOption(task.getRoleArn, "role_arn"))
|
145
|
+
.roleSessionName(
|
146
|
+
getRequiredOption(task.getRoleSessionName, "role_session_name")
|
147
|
+
)
|
148
|
+
.webIdentityTokenFile(
|
149
|
+
getRequiredOption(
|
150
|
+
task.getWebIdentityTokenFile,
|
151
|
+
"web_identity_token_file"
|
152
|
+
)
|
153
|
+
)
|
154
|
+
.build()
|
155
|
+
|
156
|
+
case "default" =>
|
157
|
+
new DefaultAWSCredentialsProviderChain
|
158
|
+
|
159
|
+
case am =>
|
160
|
+
throw new ConfigException(
|
161
|
+
s"'$am' is unsupported: `auth_method` must be one of ['basic', 'env', 'instance', 'profile', 'properties', 'anonymous', 'session', 'assume_role', 'default']."
|
162
|
+
)
|
138
163
|
}
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
164
|
+
}
|
165
|
+
|
166
|
+
private def getRequiredOption[A](o: Optional[A], name: String): A = {
|
167
|
+
o.orElseThrow(() =>
|
168
|
+
new ConfigException(
|
169
|
+
s"`$name` must be set when `auth_method` is ${task.getAuthMethod}."
|
170
|
+
)
|
171
|
+
)
|
172
|
+
}
|
146
173
|
|
147
174
|
}
|