Skip to content

Commit 275e144

Browse files
committed
refactor ec2 client creation
* remove use of deprecated AWS SDK classes * use builders for EC2 clients * some cleanup and refactoring * clarify endpoint vs region usage
1 parent 26775fa commit 275e144

File tree

7 files changed

+353
-139
lines changed

7 files changed

+353
-139
lines changed

src/main/java/com/dtolabs/rundeck/plugin/resources/ec2/EC2ResourceModelSource.java

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,16 @@
2323
*/
2424
package com.dtolabs.rundeck.plugin.resources.ec2;
2525

26-
import com.amazonaws.auth.*;
2726
import com.amazonaws.ClientConfiguration;
27+
import com.amazonaws.auth.*;
28+
import com.amazonaws.regions.RegionUtils;
29+
import com.amazonaws.regions.Regions;
2830
import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
2931
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;
30-
import com.amazonaws.services.securitytoken.model.*;
31-
import com.dtolabs.rundeck.core.common.*;
32+
import com.amazonaws.services.securitytoken.model.AssumeRoleRequest;
33+
import com.amazonaws.services.securitytoken.model.AssumeRoleResult;
34+
import com.amazonaws.services.securitytoken.model.Credentials;
35+
import com.dtolabs.rundeck.core.common.INodeSet;
3236
import com.dtolabs.rundeck.core.plugins.configuration.ConfigurationException;
3337
import com.dtolabs.rundeck.core.resources.ResourceModelSource;
3438
import com.dtolabs.rundeck.core.resources.ResourceModelSourceException;
@@ -40,7 +44,9 @@
4044
import org.slf4j.LoggerFactory;
4145

4246
import java.io.*;
43-
import java.util.*;
47+
import java.util.ArrayList;
48+
import java.util.Collections;
49+
import java.util.Properties;
4450
import java.util.concurrent.ExecutionException;
4551
import java.util.concurrent.ExecutorService;
4652
import java.util.concurrent.Executors;
@@ -91,8 +97,7 @@ public class EC2ResourceModelSource implements ResourceModelSource {
9197
final String externalId;
9298
int pageResults;
9399

94-
AWSCredentials credentials;
95-
ClientConfiguration clientConfiguration = new ClientConfiguration();;
100+
ClientConfiguration clientConfiguration = new ClientConfiguration();
96101

97102
INodeSet iNodeSet;
98103
static final Properties defaultMapping = new Properties();
@@ -153,6 +158,7 @@ public class EC2ResourceModelSource implements ResourceModelSource {
153158
}
154159

155160
public EC2ResourceModelSource(final Properties configuration, final Services services) {
161+
this.services = services;
156162
this.accessKey = configuration.getProperty(EC2ResourceModelSourceFactory.ACCESS_KEY);
157163
this.secretKey = configuration.getProperty(EC2ResourceModelSourceFactory.SECRET_KEY);
158164
this.region = configuration.getProperty(EC2ResourceModelSourceFactory.REGION);
@@ -202,53 +208,64 @@ public EC2ResourceModelSource(final Properties configuration, final Services ser
202208
EC2ResourceModelSourceFactory.RUNNING_ONLY));
203209
logger.info("[debug] runningOnly:" + runningOnly);
204210
}
205-
if (null != accessKey && null != secretKeyStoragePath) {
206211

207-
KeyStorageTree keyStorage = services.getService(KeyStorageTree.class);
208-
String secretKey = getPasswordFromKeyStorage(secretKeyStoragePath, keyStorage);
209212

210-
credentials = new BasicAWSCredentials(accessKey.trim(), secretKey.trim());
211-
}else if (null != accessKey && null != secretKey) {
212-
credentials = new BasicAWSCredentials(accessKey.trim(), secretKey.trim());
213-
}
214213
if (null != httpProxyHost && !"".equals(httpProxyHost)) {
215-
clientConfiguration.setProxyHost(httpProxyHost);
216-
clientConfiguration.setProxyPort(httpProxyPort);
217-
clientConfiguration.setProxyUsername(httpProxyUser);
218-
clientConfiguration.setProxyPassword(httpProxyPass);
214+
this.clientConfiguration.setProxyHost(httpProxyHost);
215+
this.clientConfiguration.setProxyPort(httpProxyPort);
216+
this.clientConfiguration.setProxyUsername(httpProxyUser);
217+
this.clientConfiguration.setProxyPassword(httpProxyPass);
219218
}
220-
queryAsync = !("true".equals(configuration.getProperty(SYNCHRONOUS_LOAD)) || refreshInterval <= 0);
221219

222-
initialize();
223-
}
220+
queryAsync = !("true".equals(configuration.getProperty(SYNCHRONOUS_LOAD)) || refreshInterval <= 0);
224221

225-
private void initialize() {
226222
final ArrayList<String> params = new ArrayList<String>();
227223
if (null != filterParams) {
228224
Collections.addAll(params, filterParams.split(";"));
229225
}
230226
loadMapping();
231227

232-
if (this.credentials == null) {
233-
if(this.externalId != null && this.assumeRoleArnCombinedWithExtId != null){
234-
this.credentials = createAwsCredentials(null, this.assumeRoleArnCombinedWithExtId, this.externalId);
235-
}
228+
mapper = new InstanceToNodeMapper(createEc2Supplier(), mapping, pageResults);
229+
mapper.setFilterParams(params);
230+
mapper.setEndpoint(endpoint);
231+
mapper.setRegion(region);
232+
mapper.setRunningStateOnly(runningOnly);
233+
}
236234

237-
if(assumeRoleArn != null) {
238-
AWSCredentialsProvider provider = null;
239-
if(this.credentials != null){
240-
provider = new AWSStaticCredentialsProvider(credentials);
241-
}
242235

243-
credentials = createAwsCredentials(provider, assumeRoleArn, null);
236+
protected AWSCredentials createCredentials() {
237+
if (null != accessKey && null != secretKeyStoragePath) {
238+
KeyStorageTree keyStorage = services.getService(KeyStorageTree.class);
239+
String secretKey = getPasswordFromKeyStorage(secretKeyStoragePath, keyStorage);
240+
return new BasicAWSCredentials(accessKey.trim(), secretKey.trim());
241+
} else if (null != accessKey && null != secretKey) {
242+
return new BasicAWSCredentials(accessKey.trim(), secretKey.trim());
243+
}
244+
245+
AWSCredentials credentials = null;
246+
if (this.externalId != null && this.assumeRoleArnCombinedWithExtId != null) {
247+
credentials = createAwsCredentials(null, this.assumeRoleArnCombinedWithExtId, this.externalId);
248+
}
249+
250+
if (assumeRoleArn != null) {
251+
AWSCredentialsProvider provider = null;
252+
if (credentials != null) {
253+
provider = new AWSStaticCredentialsProvider(credentials);
244254
}
255+
256+
return createAwsCredentials(provider, assumeRoleArn, null);
245257
}
258+
return credentials;
259+
}
246260

247-
mapper = new InstanceToNodeMapper(this.credentials, mapping, clientConfiguration, pageResults);
248-
mapper.setFilterParams(params);
249-
mapper.setEndpoint(endpoint);
250-
mapper.setRegion(region);
251-
mapper.setRunningStateOnly(runningOnly);
261+
262+
private EC2SupplierImpl createEc2Supplier() {
263+
return new EC2SupplierImpl(
264+
createCredentials(),
265+
clientConfiguration,
266+
// Use old default us-east-1 for AWS EC2, to maintain default behavior for existing configurations
267+
RegionUtils.getRegion(Regions.US_EAST_1.getName())
268+
);
252269
}
253270

254271
private AWSCredentials createAwsCredentials(AWSCredentialsProvider provider, String assumeRoleArn, String externalId) {

src/main/java/com/dtolabs/rundeck/plugin/resources/ec2/EC2ResourceModelSourceFactory.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@ public class EC2ResourceModelSourceFactory implements ResourceModelSourceFactory
7777
public static final String HTTP_PROXY_PASS = "httpProxyPass";
7878
public static final String MAX_RESULTS = "pageResults";
7979

80+
public EC2ResourceModelSourceFactory() {
81+
82+
}
8083
public EC2ResourceModelSourceFactory(final Framework framework) {
81-
this.framework = framework;
8284
}
8385

8486
public ResourceModelSource createResourceModelSource(Services services, final Properties configuration) throws ConfigurationException {
@@ -92,6 +94,10 @@ public ResourceModelSource createResourceModelSource(Properties configuration) t
9294
}
9395

9496
static Description DESC = DescriptionBuilder.builder()
97+
98+
public static final Map<String, Object> PASSWORD_OPTIONS = Collections.singletonMap(StringRenderingConstants.DISPLAY_TYPE_KEY, StringRenderingConstants.DisplayType.PASSWORD);
99+
100+
public static final Description DESC = DescriptionBuilder.builder()
95101
.name(PROVIDER_NAME)
96102
.title("AWS EC2 Resources")
97103
.description("Produces nodes from AWS EC2")
@@ -106,7 +112,7 @@ public ResourceModelSource createResourceModelSource(Properties configuration) t
106112
null,
107113
null,
108114
null,
109-
Collections.singletonMap("displayType", (Object) StringRenderingConstants.DisplayType.PASSWORD)
115+
PASSWORD_OPTIONS
110116
)
111117
)
112118
.property(
@@ -118,11 +124,11 @@ public ResourceModelSource createResourceModelSource(Properties configuration) t
118124
null,
119125
null,
120126
null,
121-
new HashMap<String, Object>(){{
122-
put(StringRenderingConstants.SELECTION_ACCESSOR_KEY,StringRenderingConstants.SelectionAccessor.STORAGE_PATH);
123-
put(StringRenderingConstants.STORAGE_PATH_ROOT_KEY,"keys");
124-
put(StringRenderingConstants.STORAGE_FILE_META_FILTER_KEY, "Rundeck-data-type=password");
125-
}}
127+
Map.of(
128+
StringRenderingConstants.SELECTION_ACCESSOR_KEY, StringRenderingConstants.SelectionAccessor.STORAGE_PATH,
129+
StringRenderingConstants.STORAGE_PATH_ROOT_KEY, "keys",
130+
StringRenderingConstants.STORAGE_FILE_META_FILTER_KEY, "Rundeck-data-type=password"
131+
)
126132
)
127133
)
128134
.property(
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.dtolabs.rundeck.plugin.resources.ec2;
2+
3+
import com.amazonaws.services.ec2.AmazonEC2;
4+
5+
/**
6+
* Interface for supplying AmazonEC2 clients
7+
*/
8+
public interface EC2Supplier {
9+
/**
10+
* Return an AmazonEC2 client for the default region
11+
*
12+
* @return AmazonEC2 client
13+
*/
14+
AmazonEC2 getEC2ForDefaultRegion();
15+
16+
/**
17+
* Return an AmazonEC2 client for the specified region
18+
*
19+
* @param region region name
20+
* @return AmazonEC2 client
21+
*/
22+
AmazonEC2 getEC2ForRegion(String region);
23+
24+
/**
25+
* Return an AmazonEC2 client for the specified endpoint
26+
*
27+
* @param endpoint endpoint URL
28+
* @return AmazonEC2 client
29+
*/
30+
AmazonEC2 getEC2ForEndpoint(String endpoint);
31+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.dtolabs.rundeck.plugin.resources.ec2;
2+
3+
import com.amazonaws.ClientConfiguration;
4+
import com.amazonaws.auth.AWSCredentials;
5+
import com.amazonaws.auth.AWSStaticCredentialsProvider;
6+
import com.amazonaws.client.builder.AwsClientBuilder;
7+
import com.amazonaws.regions.Region;
8+
import com.amazonaws.regions.Regions;
9+
import com.amazonaws.services.ec2.AmazonEC2;
10+
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
11+
12+
13+
/**
14+
* Implementation of EC2Supplier, uses the AWS SDK to create AmazonEC2 clients via the AmazonEC2ClientBuilder
15+
*/
16+
public class EC2SupplierImpl implements EC2Supplier {
17+
final private AWSCredentials credentials;
18+
final private ClientConfiguration clientConfiguration;
19+
final private Region defaultRegion;
20+
21+
/**
22+
* Create an instance with the specified credentials and client configuration
23+
*
24+
* @param credentials AWS credentials
25+
* @param clientConfiguration client configuration
26+
* @param region default region
27+
*/
28+
public EC2SupplierImpl(AWSCredentials credentials, ClientConfiguration clientConfiguration, Region region) {
29+
this.credentials = credentials;
30+
this.clientConfiguration = clientConfiguration;
31+
this.defaultRegion = region;
32+
}
33+
34+
@Override
35+
public AmazonEC2 getEC2ForDefaultRegion() {
36+
return getEC2ForRegion(null);
37+
}
38+
39+
/**
40+
* Return an AmazonEC2 client for the specified region, if the region is null, the default region is used
41+
*
42+
* @param region region name
43+
* @return AmazonEC2 client
44+
*/
45+
@Override
46+
public AmazonEC2 getEC2ForRegion(String region) {
47+
if (null == region) {
48+
region = defaultRegion.getName();
49+
}
50+
AmazonEC2ClientBuilder builder = AmazonEC2ClientBuilder.standard().withRegion(region).withClientConfiguration(clientConfiguration);
51+
if (null != credentials) {
52+
builder.withCredentials(new AWSStaticCredentialsProvider(credentials));
53+
}
54+
return builder.build();
55+
}
56+
57+
@Override
58+
public AmazonEC2 getEC2ForEndpoint(String endpoint) {
59+
if (null == endpoint) {
60+
return getEC2ForDefaultRegion();
61+
}
62+
AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(endpoint, null);
63+
AmazonEC2ClientBuilder amazonEC2ClientBuilder = AmazonEC2ClientBuilder.standard().withEndpointConfiguration(endpointConfiguration);
64+
if (null != credentials) {
65+
amazonEC2ClientBuilder.withCredentials(new AWSStaticCredentialsProvider(credentials));
66+
}
67+
if (null != clientConfiguration) {
68+
amazonEC2ClientBuilder.withClientConfiguration(clientConfiguration);
69+
}
70+
return amazonEC2ClientBuilder.build();
71+
}
72+
}

0 commit comments

Comments
 (0)