Skip to content

Commit cd6de9a

Browse files
authored
aws: use paginator API, fix timestamp serialization (#156)
1 parent 5d5f902 commit cd6de9a

File tree

6 files changed

+172
-22
lines changed

6 files changed

+172
-22
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Change log
22

3+
## [2.3.1] - Unreleased
4+
5+
### Changed
6+
7+
- aws: use paginator API, fix timestamp serialization
8+
([#155](https://github.com/walmartlabs/concord-plugins/pull/155)).
9+
10+
11+
312
## [2.3.0] - 2024-06-20
413

514
- aws: add a basic ecr describe-images wrapper

tasks/aws/examples/ecr/concord.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
configuration:
22
runtime: concord-v2
33
dependencies:
4-
- mvn://com.walmartlabs.concord.plugins:aws-tasks:2.3.0
4+
- mvn://com.walmartlabs.concord.plugins:aws-tasks:2.3.1
55

66
flows:
77
default:
@@ -10,5 +10,6 @@ flows:
1010
action: describe-images
1111
region: us-east-1
1212
repositoryName: foo
13+
maxResults: 1
1314
out: result
1415
- log: "Image Details: ${resource.prettyPrintJson(result.imageDetails)}"

tasks/aws/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
<groupId>software.amazon.awssdk</groupId>
3434
<artifactId>ecr</artifactId>
3535
</dependency>
36+
<dependency>
37+
<groupId>software.amazon.awssdk</groupId>
38+
<artifactId>sdk-core</artifactId>
39+
</dependency>
3640
<dependency>
3741
<groupId>software.amazon.awssdk</groupId>
3842
<artifactId>aws-core</artifactId>

tasks/aws/src/main/java/com/walmartlabs/concord/plugins/aws/EcrTask.java

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@
2323
import com.fasterxml.jackson.databind.ObjectMapper;
2424
import com.fasterxml.jackson.databind.SerializationFeature;
2525
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
26+
import com.walmartlabs.concord.runtime.v2.sdk.Context;
2627
import com.walmartlabs.concord.runtime.v2.sdk.Task;
2728
import com.walmartlabs.concord.runtime.v2.sdk.TaskResult;
2829
import com.walmartlabs.concord.runtime.v2.sdk.Variables;
2930
import org.slf4j.Logger;
3031
import org.slf4j.LoggerFactory;
3132
import software.amazon.awssdk.regions.Region;
3233
import software.amazon.awssdk.services.ecr.EcrClient;
34+
import software.amazon.awssdk.services.ecr.model.DescribeImagesRequest;
35+
import software.amazon.awssdk.services.ecr.model.ImageDetail;
3336

3437
import javax.inject.Inject;
3538
import javax.inject.Named;
@@ -42,13 +45,16 @@ public class EcrTask implements Task {
4245

4346
private static final Logger log = LoggerFactory.getLogger(EcrTask.class);
4447

48+
private final Context context;
4549
private final ObjectMapper objectMapper;
4650

4751
@Inject
48-
public EcrTask(ObjectMapper objectMapper) {
52+
public EcrTask(Context context, ObjectMapper objectMapper) {
53+
this.context = context;
4954
this.objectMapper = requireNonNull(objectMapper).copy()
5055
.registerModule(new JavaTimeModule())
51-
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
56+
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
57+
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
5258
}
5359

5460
@Override
@@ -63,29 +69,38 @@ public TaskResult execute(Variables input) {
6369
private TaskResult describeImages(Variables input) {
6470
var region = assertRegion(input, "region");
6571
var repositoryName = input.assertString("repositoryName");
66-
var verbose = input.getBoolean("verbose", false);
72+
var maxResults = input.getInt("maxResults", 100);
73+
var debug = input.getBoolean("debug", context.processConfiguration().debug());
6774

68-
// create the client
69-
if (verbose) {
70-
log.info("Using region: {}", region);
75+
if (debug) {
76+
log.info("Using region={}, maxResults={}", region, maxResults);
7177
}
72-
var client = EcrClient.builder()
78+
79+
try (var client = EcrClient.builder()
7380
.region(region)
74-
.build();
81+
.build()) {
7582

76-
// describe-images
77-
if (verbose) {
78-
log.info("Describing images in repository '{}'", repositoryName);
79-
}
80-
var result = client.describeImages(r -> r.repositoryName(repositoryName));
81-
if (verbose) {
82-
log.info("Done: {}", result.imageDetails().size());
83-
}
83+
if (debug) {
84+
log.info("Describing images in repository '{}'", repositoryName);
85+
}
86+
87+
var request = DescribeImagesRequest.builder()
88+
.repositoryName(repositoryName)
89+
.maxResults(maxResults)
90+
.build();
8491

85-
// serialize result into POJOs
86-
var data = objectMapper.convertValue(result.toBuilder(), Map.class);
87-
//noinspection unchecked
88-
return TaskResult.success().values(data);
92+
var data = client.describeImagesPaginator(request).stream()
93+
.flatMap(response -> response.imageDetails().stream())
94+
.map(ImageDetail::toBuilder)
95+
.map(b -> (Map<?, ?>) objectMapper.convertValue(b, Map.class))
96+
.toList();
97+
98+
if (debug) {
99+
log.info("Done: {}", data.size());
100+
}
101+
102+
return TaskResult.success().values(Map.of("imageDetails", data));
103+
}
89104
}
90105

91106
private static Region assertRegion(Variables input, String key) {

tasks/aws/src/test/java/com/walmartlabs/concord/plugins/aws/EcrTaskTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class EcrTaskTest {
3636

3737
@Test
3838
public void testDescribeImages() {
39-
var task = new EcrTask(new ObjectMapper());
39+
var task = new EcrTask(new MockContext(), new ObjectMapper());
4040
var input = new MapBackedVariables(Map.of(
4141
"action", "describe-images",
4242
"region", "us-east-1",
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package com.walmartlabs.concord.plugins.aws;
2+
3+
/*-
4+
* *****
5+
* Concord
6+
* -----
7+
* Copyright (C) 2017 - 2021 Walmart Inc., Concord Authors
8+
* -----
9+
* Licensed under the Apache License, Version 2.0 (the "License");
10+
* you may not use this file except in compliance with the License.
11+
* You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS,
17+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
* See the License for the specific language governing permissions and
19+
* limitations under the License.
20+
* =====
21+
*/
22+
23+
import com.walmartlabs.concord.runtime.v2.sdk.Compiler;
24+
import com.walmartlabs.concord.runtime.v2.sdk.*;
25+
26+
import java.io.Serializable;
27+
import java.nio.file.Path;
28+
import java.util.Map;
29+
import java.util.UUID;
30+
31+
public class MockContext implements Context {
32+
private final Variables variables;
33+
private final Variables defaultVariables;
34+
35+
public MockContext() {
36+
this(Map.of(), Map.of());
37+
}
38+
39+
public MockContext(Map<String, Object> vars, Map<String, Object> defs) {
40+
this.variables = new MapBackedVariables(vars);
41+
this.defaultVariables = new MapBackedVariables(defs);
42+
}
43+
44+
@Override
45+
public Path workingDirectory() {
46+
return null;
47+
}
48+
49+
@Override
50+
public UUID processInstanceId() {
51+
return null;
52+
}
53+
54+
@Override
55+
public Variables variables() {
56+
return variables;
57+
}
58+
59+
@Override
60+
public Variables defaultVariables() {
61+
return defaultVariables;
62+
}
63+
64+
@Override
65+
public FileService fileService() {
66+
return null;
67+
}
68+
69+
@Override
70+
public DockerService dockerService() {
71+
return null;
72+
}
73+
74+
@Override
75+
public SecretService secretService() {
76+
return null;
77+
}
78+
79+
@Override
80+
public LockService lockService() {
81+
return null;
82+
}
83+
84+
@Override
85+
public ApiConfiguration apiConfiguration() {
86+
return null;
87+
}
88+
89+
@Override
90+
public ProcessConfiguration processConfiguration() {
91+
return ProcessConfiguration.builder().build();
92+
}
93+
94+
@Override
95+
public Execution execution() {
96+
return null;
97+
}
98+
99+
@Override
100+
public Compiler compiler() {
101+
return null;
102+
}
103+
104+
@Override
105+
public <T> T eval(Object o, Class<T> aClass) {
106+
return null;
107+
}
108+
109+
@Override
110+
public <T> T eval(Object o, Map<String, Object> map, Class<T> aClass) {
111+
return null;
112+
}
113+
114+
@Override
115+
public void suspend(String s) {
116+
}
117+
118+
@Override
119+
public void reentrantSuspend(String s, Map<String, Serializable> map) {
120+
}
121+
}

0 commit comments

Comments
 (0)