Skip to content

Commit 364a97c

Browse files
committed
refactor code to accommodate edge port config for all services (localstack#20)
1 parent cea9939 commit 364a97c

16 files changed

+244
-189
lines changed

README.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import cloud.localstack.TestUtils;
2626
import cloud.localstack.docker.annotation.LocalstackDockerProperties;
2727
2828
@RunWith(LocalstackTestRunner.class)
29-
@LocalstackDockerProperties(services = { "s3", "sqs", "kinesis:77077" })
29+
@LocalstackDockerProperties(services = { "s3", "sqs", "kinesis" })
3030
public class MyCloudAppTest {
3131
3232
@Test
@@ -39,7 +39,7 @@ public class MyCloudAppTest {
3939
}
4040
```
4141

42-
Or with JUnit 5 :
42+
Or with JUnit 5:
4343

4444
```
4545
@ExtendWith(LocalstackDockerExtension.class)
@@ -58,7 +58,7 @@ Simply add the following dependency to your `pom.xml` file:
5858
<dependency>
5959
<groupId>cloud.localstack</groupId>
6060
<artifactId>localstack-utils</artifactId>
61-
<version>0.2.1</version>
61+
<version>0.2.2</version>
6262
</dependency>
6363
```
6464

@@ -69,17 +69,24 @@ You can configure the Docker behaviour using the `@LocalstackDockerProperties` a
6969
| property | usage | type | default value |
7070
|-----------------------------|------------------------------------------------------------------------------------------------------------------------------|------------------------------|---------------|
7171
| `pullNewImage` | Determines if a new image is pulled from the docker repo before the tests are run. | boolean | `false` |
72-
| `randomizePorts` | Determines if the container should expose the default local stack ports (4567-4583) or if it should expose randomized ports. | boolean | `false` |
7372
| `services` | Determines which services should be run when the localstack starts. | String[] | All |
7473
| `imageTag` | Use a specific image tag for docker container | String | `latest` |
7574
| `hostNameResolver` | Used for determining the host name of the machine running the docker containers so that the containers can be addressed. | IHostNameResolver | `localhost` |
7675
| `environmentVariableProvider` | Used for injecting environment variables into the container. | IEnvironmentVariableProvider | Empty Map |
7776
| `useSingleDockerContainer` | Whether a singleton container should be used by all test classes. | boolean | `false` |
7877

79-
_Note: When specifying the port in the `services` property, you cannot use `randomizePorts = true`_
80-
8178
For more details, please refer to the README of the main LocalStack repo: https://github.com/localstack/localstack
8279

80+
### Deprecated Configurations
81+
82+
Due to recent changes in LocalStack (e.g., exposing all services via a single edge port, `4566`), the following configuration parameters are now deprecated in the latest version:
83+
84+
| property | usage | type | default value |
85+
|-----------------------------|------------------------------------------------------------------------------------------------------------------------------|------------------------------|---------------|
86+
| `randomizePorts` | Determines if the container should expose the default local stack ports (4567-4583) or if it should expose randomized ports. | boolean | `false` |
87+
88+
_Note: When specifying the port in the `services` property, you cannot use `randomizePorts = true`_
89+
8390
## Building
8491

8592
To build the latest version of the code via Maven:
@@ -89,11 +96,12 @@ make build
8996

9097
## Change Log
9198

92-
* v0.2.2: Addition of CloudWatch Logs endpoint configuration
99+
* v0.2.2: Addition of CloudWatch Logs endpoint configuration; adjust tests to use central edge service endpoint
93100
* v0.2.1: Move Java sources into separate project; mark non-Docker Java `LocalstackExtension` as deprecated; update paths for Python code lookup in Docker container
101+
* v0.2.0: Last version still maintained in LocalStack main repo
94102

95103
## License
96104

97-
Copyright (c) 2017-2020 LocalStack maintainers and contributors.
105+
Copyright (c) LocalStack maintainers and contributors.
98106

99107
This version of LocalStack is released under the Apache License, Version 2.0 (see LICENSE.txt).

src/main/java/cloud/localstack/Constants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ public class Constants {
88

99
public static final String LOCALHOST_DOMAIN_NAME = "localhost.localstack.cloud";
1010

11+
public static final String DEFAULT_AWS_ACCOUNT_ID = "000000000000";
12+
1113
public static final String DEFAULT_REGION = "us-east-1";
1214
public static final String TEST_ACCESS_KEY = "test";
1315
public static final String TEST_SECRET_KEY = "test";

src/main/java/cloud/localstack/Localstack.java

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,21 @@
2323
*/
2424
public class Localstack {
2525

26+
public static final String ENV_CONFIG_USE_SSL = "USE_SSL";
27+
public static final String ENV_CONFIG_EDGE_PORT = "EDGE_PORT";
28+
2629
private static final Logger LOG = Logger.getLogger(Localstack.class.getName());
2730

31+
private static final Pattern READY_TOKEN = Pattern.compile("Ready\\.");
32+
33+
private static final int DEFAULT_EDGE_PORT = 4566;
34+
2835
private static final String PORT_CONFIG_FILENAME = "/opt/code/localstack/" +
2936
".venv/lib/python3.8/site-packages/localstack_client/config.py";
3037

31-
private static final Pattern READY_TOKEN = Pattern.compile("Ready\\.");
32-
3338
//Regular expression used to parse localstack config to determine default ports for services
3439
private static final Pattern DEFAULT_PORT_PATTERN = Pattern.compile("'(\\w+)'\\Q: '{proto}://{host}:\\E(\\d+)'");
3540

36-
private static final int SERVICE_NAME_GROUP = 1;
37-
38-
private static final int PORT_GROUP = 2;
39-
40-
public static final String ENV_CONFIG_USE_SSL = "USE_SSL";
41-
4241
private Container localStackContainer;
4342

4443
/**
@@ -99,12 +98,16 @@ public void stop() {
9998
locked = false;
10099
}
101100

101+
public boolean isRunning() {
102+
return localStackContainer == null ? false : localStackContainer.isRunning();
103+
}
104+
102105
private void loadServiceToPortMap() {
103106
String localStackPortConfig = localStackContainer.executeCommand(Arrays.asList("cat", PORT_CONFIG_FILENAME));
104107

108+
int edgePort = getEdgePort();
105109
Map<String, Integer> ports = new RegexStream(DEFAULT_PORT_PATTERN.matcher(localStackPortConfig)).stream()
106-
.collect(Collectors.toMap(match -> match.group(SERVICE_NAME_GROUP),
107-
match -> Integer.parseInt(match.group(PORT_GROUP))));
110+
.collect(Collectors.toMap(match -> match.group(1), match -> edgePort));
108111

109112
serviceToPortMap = Collections.unmodifiableMap(ports);
110113
}
@@ -121,6 +124,11 @@ public String getEndpointS3() {
121124
return s3Endpoint;
122125
}
123126

127+
public int getEdgePort() {
128+
String envEdgePort = System.getenv(ENV_CONFIG_EDGE_PORT);
129+
return envEdgePort == null ? DEFAULT_EDGE_PORT : Integer.parseInt(envEdgePort);
130+
}
131+
124132
public String getEndpointKinesis() {
125133
return endpointForService(ServiceName.KINESIS);
126134
}
@@ -172,7 +180,7 @@ public String getEndpointCloudWatch() {
172180
public String getEndpointCloudWatchLogs() {
173181
return endpointForService(ServiceName.CLOUDWATCH_LOGS);
174182
}
175-
183+
176184
public String getEndpointSES() {
177185
return endpointForService(ServiceName.SES);
178186
}
@@ -206,6 +214,10 @@ public String getEndpointIAM() {
206214
}
207215

208216
public String endpointForService(String serviceName) {
217+
return endpointForPort(getServicePort(serviceName));
218+
}
219+
220+
public int getServicePort(String serviceName) {
209221
if (serviceToPortMap == null) {
210222
throw new IllegalStateException("Service to port mapping has not been determined yet.");
211223
}
@@ -214,8 +226,7 @@ public String endpointForService(String serviceName) {
214226
throw new IllegalArgumentException("Unknown port mapping for service: " + serviceName);
215227
}
216228

217-
int internalPort = serviceToPortMap.get(serviceName);
218-
return endpointForPort(internalPort);
229+
return serviceToPortMap.get(serviceName);
219230
}
220231

221232
public String endpointForPort(int port) {

src/main/java/cloud/localstack/docker/Container.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ public class Container {
2222
private static final Logger LOG = Logger.getLogger(Container.class.getName());
2323

2424
private static final String LOCALSTACK_NAME = "localstack/localstack";
25-
private static final String LOCALSTACK_PORTS = "4566-4593";
25+
private static final String LOCALSTACK_PORT_EDGE = "4566";
26+
private static final String LOCALSTACK_PORT_ELASTICSEARCH = "4571";
2627

2728
private static final int MAX_PORT_CONNECTION_ATTEMPTS = 10;
28-
2929
private static final int MAX_LOG_COLLECTION_ATTEMPTS = 120;
3030
private static final long POLL_INTERVAL = 1000;
3131
private static final int NUM_LOG_LINES = 10;
@@ -66,7 +66,8 @@ public static Container createLocalstackContainer(
6666
}
6767

6868
RunCommand runCommand = new RunCommand(LOCALSTACK_NAME, imageTag)
69-
.withExposedPorts(LOCALSTACK_PORTS, randomizePorts)
69+
.withExposedPorts(LOCALSTACK_PORT_EDGE, randomizePorts)
70+
.withExposedPorts(LOCALSTACK_PORT_ELASTICSEARCH, randomizePorts)
7071
.withEnvironmentVariable(LOCALSTACK_EXTERNAL_HOSTNAME, externalHostName)
7172
.withEnvironmentVariable(ENV_DEBUG, ENV_DEBUG_DEFAULT)
7273
.withEnvironmentVariable(ENV_USE_SSL, Localstack.INSTANCE.useSSL() ? "1" : "0")
@@ -82,7 +83,6 @@ public static Container createLocalstackContainer(
8283
return result;
8384
}
8485

85-
8686
public static Container getRunningLocalstackContainer() {
8787
return getRunningLocalstackContainer(DEFAULT_CONTAINER_ID);
8888
}
@@ -134,6 +134,15 @@ private boolean isPortOpen(String ip, PortMapping port) {
134134
}
135135
}
136136

137+
public boolean isRunning() {
138+
try {
139+
new PortCommand(containerId).execute();
140+
return true;
141+
} catch(Exception e) {
142+
return false;
143+
}
144+
}
145+
137146
/**
138147
* Poll the docker logs until a specific token appears, then return. Primarily
139148
* used to look for the "Ready." token in the LocalStack logs.

src/main/java/cloud/localstack/docker/LocalstackDockerExtension.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ public void beforeAll(final ExtensionContext context) throws Exception {
3737
} else {
3838
store = context.getStore(NAMESPACE);
3939
}
40-
if (store.get("localstack") == null) {
41-
final StartedLocalStack startedStack = new LocalstackDockerExtension.StartedLocalStack(context);
42-
store.getOrComputeIfAbsent("localstack", key -> startedStack);
40+
StartedLocalStack startedStack = (StartedLocalStack)store.get("localstack");
41+
if (startedStack == null || !startedStack.isRunning()) {
42+
final StartedLocalStack newStartedStack = new LocalstackDockerExtension.StartedLocalStack(context);
43+
store.put("localstack", newStartedStack);
4344
}
4445
}
4546

@@ -56,6 +57,10 @@ static class StartedLocalStack implements ExtensionContext.Store.CloseableResour
5657
localstackDocker.startup(dockerConfig);
5758
}
5859

60+
public boolean isRunning() {
61+
return localstackDocker.isRunning();
62+
}
63+
5964
@Override
6065
public void close() throws Throwable {
6166
localstackDocker.stop();

src/main/java/cloud/localstack/docker/annotation/LocalstackDockerAnnotationProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ private String getExternalHostName(final LocalstackDockerProperties properties)
7575

7676
final String externalHostName = StringUtils.defaultIfBlank(resolvedName, "localhost");
7777

78-
LOG.info("External host name is set to: " + externalHostName);
78+
LOG.fine("External host name is set to: " + externalHostName);
7979
return externalHostName;
8080
} catch (InstantiationException | IllegalAccessException ex) {
8181
throw new IllegalStateException("Unable to resolve hostname", ex);

src/main/java/cloud/localstack/docker/annotation/LocalstackDockerProperties.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@
3333

3434
/**
3535
* Determines if the container should expose the default local stack ports (4567-4583) or if it should expose randomized ports
36-
* in order to prevent conflicts with other localstack containers running on the same machine
36+
* in order to prevent conflicts with other localstack containers running on the same machine.
37+
*
38+
* Deprecated, since latest LocalStack is using a single entry point (edge service)
3739
*/
40+
@Deprecated
3841
boolean randomizePorts() default false;
3942

4043
/**

src/main/java/cloud/localstack/docker/command/PortCommand.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public List<PortMapping> execute() {
3030
.collect(Collectors.toList());
3131
}
3232

33-
private Function<MatchResult, PortMapping> matchToPortMapping = m -> new PortMapping(m.group(IP_GROUP), m.group(EXTERNAL_PORT_GROUP), m.group(INTERNAL_PORT_GROUP));
33+
private Function<MatchResult, PortMapping> matchToPortMapping = m ->
34+
new PortMapping(m.group(IP_GROUP), m.group(EXTERNAL_PORT_GROUP), m.group(INTERNAL_PORT_GROUP));
3435

3536
}

0 commit comments

Comments
 (0)