embulk-executor-remoteserver 0.2.1 → 0.3.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/.circleci/config.yml +1 -0
- data/.gitignore +2 -0
- data/README.md +22 -3
- data/build.gradle +7 -7
- data/docker-compose.test.yml +49 -0
- data/example/Gemfile +5 -0
- data/example/README.md +32 -0
- data/example/config.yml +25 -0
- data/example/docker-compse.yml +8 -0
- data/example/work/input_1.json +1 -0
- data/example/work/input_2.json +1 -0
- data/gradle.properties +1 -1
- data/gradle/dependency-locks/compileClasspath.lockfile +3 -7
- data/gradle/dependency-locks/testCompileClasspath.lockfile +4 -8
- data/src/main/java/org/embulk/executor/remoteserver/ClientSession.java +7 -2
- data/src/main/java/org/embulk/executor/remoteserver/EmbulkClient.java +7 -2
- data/src/main/java/org/embulk/executor/remoteserver/EmbulkServer.java +7 -1
- data/src/main/java/org/embulk/executor/remoteserver/Launcher.java +31 -5
- data/src/main/java/org/embulk/executor/remoteserver/P12File.java +28 -0
- data/src/main/java/org/embulk/executor/remoteserver/RemoteServerExecutor.java +50 -3
- data/src/main/java/org/embulk/executor/remoteserver/ServerSession.java +1 -1
- data/src/main/java/org/embulk/executor/remoteserver/TLSConfig.java +74 -0
- data/src/test/java/org/embulk/executor/remoteserver/TestRemoteServerExecutor.java +42 -25
- data/src/test/resources/config/exec_base.yml +5 -0
- data/src/test/resources/config/exec_tls.yml +13 -0
- data/src/test/resources/config/filter.yml +3 -0
- data/src/test/resources/config/input.yml +6 -0
- data/src/test/resources/config/output.yml +7 -0
- data/test/setup.sh +7 -1
- metadata +18 -7
- data/docker-compose.yml +0 -24
- data/test/Gemfile.lock +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c835aba3fc2c0ce9c17fa5d9fe70c756097081a
|
4
|
+
data.tar.gz: 5831d9e3268af8ef640e1910c0ed1b86eaec88d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46a1920c3c054f3d7b68c05308c38d4ab3ff3d4b6dd940733e29b5917803f2ce7a5a031efa214ebce2a76f8a3eb1929756fe9f7bc5d5bc9bccbcee148497b1ef
|
7
|
+
data.tar.gz: 0de6447bb0d0b7756fdb6e2dcc30eeb82a52f589a51e50fc67b1cbfa7308a5bce4e648d4420079cc8711b5c0ec00912f024bbb1508f1b490be64accabac82d63
|
data/.circleci/config.yml
CHANGED
@@ -10,6 +10,7 @@ jobs:
|
|
10
10
|
- v1-gradle-{{ checksum "gradle/dependency-locks/compileClasspath.lockfile" }}-{{ checksum "gradle/dependency-locks/testCompileClasspath.lockfile" }}
|
11
11
|
- v1-gradle-
|
12
12
|
- run: ./test/setup.sh
|
13
|
+
- run: sudo chown -R circleci.circleci tmp/certs
|
13
14
|
- run: ./gradlew check --info
|
14
15
|
- run:
|
15
16
|
name: Save test results
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -8,12 +8,19 @@ Embulk executor plugin to run Embulk tasks on remote servers.
|
|
8
8
|
|
9
9
|
### Notes
|
10
10
|
- It's still very experimental version, so might change its spec without notification.
|
11
|
-
- It might have
|
11
|
+
- It might have some issues or bugs. I would appreciate it if you use this and give me reports/feedback!
|
12
12
|
|
13
13
|
## Configuration
|
14
14
|
|
15
|
-
- **hosts**: List of remote servers (`hostname` or `hostname:port`, default port is `30001`). If not specified, the executor runs as local mode, which
|
15
|
+
- **hosts**: List of remote servers (`hostname` or `hostname:port`, default port is `30001`). If not specified, the executor runs as the local mode, which starts an Embulk server on its own process (array of string)
|
16
16
|
- **timeout_seconds**: Timeout seconds of the whole execution (integer, default: `3600`)
|
17
|
+
- **tls**: Enable to connect server over TLS (boolean, default: `false`)
|
18
|
+
- **key_store_p12**: Information of a P12 file used as a [KeyManager](https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/KeyManager.html) to register your client certificate. It would be needed when client auth mode is enabled on Embulk server.
|
19
|
+
- **path**: Path of the file (string, required)
|
20
|
+
- **password**: Password of the file (string, required)
|
21
|
+
- **trust_store_p12**: Information of a P12 file used as a [TrustManager](https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/TrustManager.html) to register a CA certificate. It would be needed when Embulk server uses unknown CA's certificate.
|
22
|
+
- **path**: Path of the file (string, required)
|
23
|
+
- **password**: Password of the file (string, required)
|
17
24
|
|
18
25
|
## Example
|
19
26
|
|
@@ -27,7 +34,7 @@ exec:
|
|
27
34
|
```
|
28
35
|
|
29
36
|
## Embulk server
|
30
|
-
The server
|
37
|
+
The server receives requests from client (Embulk) and run Embulk tasks, then returns results to client. It communicates with clients via `TCP 30001 port`.
|
31
38
|
|
32
39
|
### Running Embulk server as a Docker container
|
33
40
|
The image is hosted by [DockerHub](https://hub.docker.com/r/kamatama41/embulk-executor-remoteserver).
|
@@ -37,6 +44,18 @@ You can try running Embulk server by the following command.
|
|
37
44
|
$ docker run --rm -p 30001:30001 kamatama41/embulk-executor-remoteserver
|
38
45
|
```
|
39
46
|
|
47
|
+
### Configure Embulk server
|
48
|
+
There are some environment variables to configure the server
|
49
|
+
|
50
|
+
- `BIND_ADDRESS`: Bind address of the server (default: `0.0.0.0`)
|
51
|
+
- `PORT`: Port number to listen (default: `30001`)
|
52
|
+
- `ENABLE_TLS`: Try to connect to client via TLS if `true` (default: `false`)
|
53
|
+
- `ENABLE_TLS_CLIENT_AUTH`: Require client authentication if `true` (default: `false`)
|
54
|
+
- `KEY_P12_PATH`: Path of the P12 file used as a KeyManager
|
55
|
+
- `KEY_P12_PASSWORD`: Password of the Key P12 file
|
56
|
+
- `TRUST_P12_PATH`: Path of the P12 file used as a TrustManager
|
57
|
+
- `TRUST_P12_PASSWORD`: Password of the Trust P12 file
|
58
|
+
|
40
59
|
## Build
|
41
60
|
|
42
61
|
```
|
data/build.gradle
CHANGED
@@ -21,20 +21,20 @@ configurations {
|
|
21
21
|
}
|
22
22
|
|
23
23
|
dependencies {
|
24
|
-
compile("com.github.kamatama41:nsocket:0.
|
24
|
+
compile("com.github.kamatama41:nsocket:0.3.4") {
|
25
25
|
// Use embulk-core's Jackson (2.6.7) instead
|
26
26
|
exclude group: "com.fasterxml.jackson.core", module: "jackson-databind"
|
27
27
|
}
|
28
28
|
// Followings are needed for running EmbulkServer
|
29
|
-
implementation "org.embulk:embulk-standards:0.9.
|
30
|
-
serverRuntime "org.embulk:embulk-standards:0.9.
|
29
|
+
implementation "org.embulk:embulk-standards:0.9.17"
|
30
|
+
serverRuntime "org.embulk:embulk-standards:0.9.17"
|
31
31
|
implementation "ch.qos.logback:logback-classic:1.2.3"
|
32
32
|
serverRuntime "ch.qos.logback:logback-classic:1.2.3"
|
33
33
|
implementation "ch.qos.logback:logback-core:1.2.3"
|
34
34
|
serverRuntime "ch.qos.logback:logback-core:1.2.3"
|
35
35
|
|
36
|
-
testImplementation "org.embulk:embulk-standards:0.9.
|
37
|
-
testImplementation "org.embulk:embulk-test:0.9.
|
36
|
+
testImplementation "org.embulk:embulk-standards:0.9.17"
|
37
|
+
testImplementation "org.embulk:embulk-test:0.9.17"
|
38
38
|
testImplementation "com.github.kamatama41:embulk-test-helpers:0.8.0"
|
39
39
|
testImplementation "org.junit.jupiter:junit-jupiter-api:5.3.2"
|
40
40
|
testRuntime "org.junit.jupiter:junit-jupiter-engine:5.3.2"
|
@@ -50,7 +50,7 @@ task executableEmbulkServer(type: Jar) {
|
|
50
50
|
}
|
51
51
|
|
52
52
|
embulk {
|
53
|
-
version = "0.9.
|
53
|
+
version = "0.9.17"
|
54
54
|
category = "executor"
|
55
55
|
name = "docker"
|
56
56
|
authors = ["Shinichi Ishimura"]
|
@@ -67,4 +67,4 @@ test {
|
|
67
67
|
release {
|
68
68
|
git { requireBranch = 'master' }
|
69
69
|
}
|
70
|
-
afterReleaseBuild.dependsOn gemPush
|
70
|
+
afterReleaseBuild.dependsOn gemPush
|
@@ -0,0 +1,49 @@
|
|
1
|
+
version: '3.2'
|
2
|
+
services:
|
3
|
+
server1: &server
|
4
|
+
build:
|
5
|
+
context: .
|
6
|
+
dockerfile: Dockerfile
|
7
|
+
environment:
|
8
|
+
LOG_LEVEL: debug
|
9
|
+
ports:
|
10
|
+
- "30001:30001"
|
11
|
+
volumes:
|
12
|
+
- ./tmp/output:/output
|
13
|
+
- ./src/test/resources/json:/root/src/test/resources/json
|
14
|
+
|
15
|
+
server2:
|
16
|
+
<<: *server
|
17
|
+
ports:
|
18
|
+
- "30002:30001"
|
19
|
+
|
20
|
+
tls-server1: &tls-server
|
21
|
+
<<: *server
|
22
|
+
environment:
|
23
|
+
LOG_LEVEL: debug
|
24
|
+
ENABLE_TLS: "true"
|
25
|
+
ENABLE_TLS_CLIENT_AUTH: "true"
|
26
|
+
KEY_P12_PATH: /certs/embulk-server.local.p12
|
27
|
+
KEY_P12_PASSWORD: abcde
|
28
|
+
TRUST_P12_PATH: /certs/ca-chain.p12
|
29
|
+
TRUST_P12_PASSWORD: p@ssw0rd
|
30
|
+
ports:
|
31
|
+
- "30003:30001"
|
32
|
+
volumes:
|
33
|
+
- ./tmp/output:/output
|
34
|
+
- ./tmp/certs:/certs
|
35
|
+
- ./src/test/resources/json:/root/src/test/resources/json
|
36
|
+
|
37
|
+
tls-server2:
|
38
|
+
<<: *tls-server
|
39
|
+
ports:
|
40
|
+
- "30004:30001"
|
41
|
+
|
42
|
+
cert-generator:
|
43
|
+
image: kamatama41/test-cert-generator
|
44
|
+
volumes:
|
45
|
+
- ./tmp/certs:/root/work
|
46
|
+
environment:
|
47
|
+
SERVER_COMMON_NAME: embulk-server.local
|
48
|
+
SERVER_P12_PASSWORD: abcde
|
49
|
+
CLIENT_P12_PASSWORD: fghij
|
data/example/Gemfile
ADDED
data/example/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
## How to run
|
2
|
+
|
3
|
+
Run `embulk bundle`
|
4
|
+
|
5
|
+
```sh
|
6
|
+
$ embulk bundle --path vendor/bundle
|
7
|
+
```
|
8
|
+
|
9
|
+
Run `docker-compose up`
|
10
|
+
|
11
|
+
```sh
|
12
|
+
$ docker-compose -f docker-compse.yml up
|
13
|
+
Creating example_remote1_1 ... done
|
14
|
+
Attaching to example_remote1_1
|
15
|
+
remote1_1 | 15:11:59.045 [main] INFO c.g.kamatama41.nsocket.SocketServer - Starting server..
|
16
|
+
```
|
17
|
+
|
18
|
+
In another session, run `embulk run`
|
19
|
+
|
20
|
+
```sh
|
21
|
+
$ embulk run config.yml -b .
|
22
|
+
```
|
23
|
+
|
24
|
+
So that 2 output files would be generated in `work` directory
|
25
|
+
|
26
|
+
```sh
|
27
|
+
$ cat work/output_*
|
28
|
+
id,name,time
|
29
|
+
1,Scott,2019-04-06 15:12:42.029000 +0000
|
30
|
+
id,name,time
|
31
|
+
2,Tiger,2019-04-06 15:12:42.029000 +0000
|
32
|
+
```
|
data/example/config.yml
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
in:
|
2
|
+
type: file
|
3
|
+
path_prefix: work/input_
|
4
|
+
parser:
|
5
|
+
type: json
|
6
|
+
columns:
|
7
|
+
- {name: id, type: long}
|
8
|
+
- {name: name, type: string}
|
9
|
+
filters:
|
10
|
+
- type: add_time
|
11
|
+
to_column:
|
12
|
+
name: time
|
13
|
+
type: timestamp
|
14
|
+
from_value:
|
15
|
+
mode: upload_time
|
16
|
+
exec:
|
17
|
+
type: remoteserver
|
18
|
+
hosts:
|
19
|
+
- localhost:30001
|
20
|
+
out:
|
21
|
+
type: file
|
22
|
+
path_prefix: work/output_
|
23
|
+
file_ext: csv
|
24
|
+
formatter:
|
25
|
+
type: csv
|
@@ -0,0 +1 @@
|
|
1
|
+
{"id": 1, "name": "Scott"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"id": 2, "name": "Tiger"}
|
data/gradle.properties
CHANGED
@@ -1 +1 @@
|
|
1
|
-
version=0.
|
1
|
+
version=0.3.0
|
@@ -11,16 +11,13 @@ com.fasterxml.jackson.datatype:jackson-datatype-guava:2.6.7
|
|
11
11
|
com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.6.7
|
12
12
|
com.fasterxml.jackson.datatype:jackson-datatype-joda:2.6.7
|
13
13
|
com.fasterxml.jackson.module:jackson-module-guice:2.6.7
|
14
|
-
com.github.kamatama41:nsocket:0.
|
14
|
+
com.github.kamatama41:nsocket:0.3.4
|
15
15
|
com.google.code.findbugs:annotations:3.0.0
|
16
16
|
com.google.guava:guava:18.0
|
17
17
|
com.google.inject.extensions:guice-multibindings:4.0
|
18
18
|
com.google.inject:guice:4.0
|
19
19
|
com.ibm.icu:icu4j:54.1.1
|
20
20
|
commons-beanutils:commons-beanutils-core:1.8.3
|
21
|
-
commons-cli:commons-cli:1.3.1
|
22
|
-
commons-collections:commons-collections:3.2.1
|
23
|
-
commons-lang:commons-lang:2.4
|
24
21
|
io.airlift:slice:0.9
|
25
22
|
io.netty:netty-buffer:4.0.44.Final
|
26
23
|
io.netty:netty-common:4.0.44.Final
|
@@ -31,9 +28,8 @@ org.apache.bval:bval-core:0.5
|
|
31
28
|
org.apache.bval:bval-jsr303:0.5
|
32
29
|
org.apache.commons:commons-compress:1.10
|
33
30
|
org.apache.commons:commons-lang3:3.4
|
34
|
-
org.
|
35
|
-
org.embulk:embulk-
|
36
|
-
org.embulk:embulk-standards:0.9.16
|
31
|
+
org.embulk:embulk-core:0.9.17
|
32
|
+
org.embulk:embulk-standards:0.9.17
|
37
33
|
org.jruby:jruby-complete:9.1.15.0
|
38
34
|
org.msgpack:msgpack-core:0.8.11
|
39
35
|
org.slf4j:slf4j-api:1.7.25
|
@@ -12,16 +12,13 @@ com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.6.7
|
|
12
12
|
com.fasterxml.jackson.datatype:jackson-datatype-joda:2.6.7
|
13
13
|
com.fasterxml.jackson.module:jackson-module-guice:2.6.7
|
14
14
|
com.github.kamatama41:embulk-test-helpers:0.8.0
|
15
|
-
com.github.kamatama41:nsocket:0.
|
15
|
+
com.github.kamatama41:nsocket:0.3.4
|
16
16
|
com.google.code.findbugs:annotations:3.0.0
|
17
17
|
com.google.guava:guava:18.0
|
18
18
|
com.google.inject.extensions:guice-multibindings:4.0
|
19
19
|
com.google.inject:guice:4.0
|
20
20
|
com.ibm.icu:icu4j:54.1.1
|
21
21
|
commons-beanutils:commons-beanutils-core:1.8.3
|
22
|
-
commons-cli:commons-cli:1.3.1
|
23
|
-
commons-collections:commons-collections:3.2.1
|
24
|
-
commons-lang:commons-lang:2.4
|
25
22
|
io.airlift:slice:0.9
|
26
23
|
io.netty:netty-buffer:4.0.44.Final
|
27
24
|
io.netty:netty-common:4.0.44.Final
|
@@ -33,11 +30,10 @@ org.apache.bval:bval-core:0.5
|
|
33
30
|
org.apache.bval:bval-jsr303:0.5
|
34
31
|
org.apache.commons:commons-compress:1.10
|
35
32
|
org.apache.commons:commons-lang3:3.4
|
36
|
-
org.apache.velocity:velocity:1.7
|
37
33
|
org.apiguardian:apiguardian-api:1.0.0
|
38
|
-
org.embulk:embulk-core:0.9.
|
39
|
-
org.embulk:embulk-standards:0.9.
|
40
|
-
org.embulk:embulk-test:0.9.
|
34
|
+
org.embulk:embulk-core:0.9.17
|
35
|
+
org.embulk:embulk-standards:0.9.17
|
36
|
+
org.embulk:embulk-test:0.9.17
|
41
37
|
org.hamcrest:hamcrest-core:1.3
|
42
38
|
org.hamcrest:hamcrest-library:1.3
|
43
39
|
org.jruby:jruby-complete:9.1.15.0
|
@@ -15,7 +15,7 @@ import java.util.concurrent.TimeUnit;
|
|
15
15
|
import java.util.concurrent.TimeoutException;
|
16
16
|
import java.util.stream.Collectors;
|
17
17
|
|
18
|
-
class ClientSession {
|
18
|
+
class ClientSession implements AutoCloseable {
|
19
19
|
private static final Logger log = LoggerFactory.getLogger(ClientSession.class);
|
20
20
|
|
21
21
|
private final String id;
|
@@ -78,6 +78,11 @@ class ClientSession {
|
|
78
78
|
return isFinished;
|
79
79
|
}
|
80
80
|
|
81
|
+
@Override
|
82
|
+
public void close() {
|
83
|
+
isFinished = true;
|
84
|
+
}
|
85
|
+
|
81
86
|
synchronized void update(UpdateTaskStateData data) {
|
82
87
|
switch (data.getTaskState()) {
|
83
88
|
case STARTED:
|
@@ -115,7 +120,7 @@ class ClientSession {
|
|
115
120
|
throw new TaskExecutionException(message);
|
116
121
|
}
|
117
122
|
} finally {
|
118
|
-
|
123
|
+
close();
|
119
124
|
}
|
120
125
|
}
|
121
126
|
|
@@ -29,8 +29,12 @@ class EmbulkClient extends SocketClient implements AutoCloseable {
|
|
29
29
|
|
30
30
|
static EmbulkClient open(
|
31
31
|
ClientSession session,
|
32
|
-
List<Host> hosts
|
32
|
+
List<Host> hosts,
|
33
|
+
TLSConfig tlsConfig) throws IOException {
|
33
34
|
EmbulkClient client = new EmbulkClient(session);
|
35
|
+
if (tlsConfig != null) {
|
36
|
+
client.setSslContext(tlsConfig.getSSLContext());
|
37
|
+
}
|
34
38
|
client.open();
|
35
39
|
|
36
40
|
for (Host host : hosts) {
|
@@ -90,6 +94,7 @@ class EmbulkClient extends SocketClient implements AutoCloseable {
|
|
90
94
|
for (Connection connection : getActiveConnections()) {
|
91
95
|
connection.sendSyncCommand(RemoveSessionCommand.ID, session.getId());
|
92
96
|
}
|
97
|
+
session.close();
|
93
98
|
super.close();
|
94
99
|
}
|
95
100
|
|
@@ -99,7 +104,7 @@ class EmbulkClient extends SocketClient implements AutoCloseable {
|
|
99
104
|
if(!session.isFinished()) {
|
100
105
|
try {
|
101
106
|
// Try reconnecting
|
102
|
-
Connection newConnection = reconnect(connection);
|
107
|
+
Connection newConnection = reconnect(connection, i -> !session.isFinished());
|
103
108
|
newConnection.sendSyncCommand(InitializeSessionCommand.ID, toInitializeSessionData(session));
|
104
109
|
} catch (IOException e) {
|
105
110
|
log.warn(String.format("A connection to %s could not be reconnected.", connection.getRemoteSocketAddress()), e);
|
@@ -11,7 +11,7 @@ public class EmbulkServer implements AutoCloseable {
|
|
11
11
|
this.server = server;
|
12
12
|
}
|
13
13
|
|
14
|
-
static EmbulkServer start(String host, int port, int numOfWorkers) throws IOException {
|
14
|
+
static EmbulkServer start(String host, int port, int numOfWorkers, TLSConfig tlsConfig) throws IOException {
|
15
15
|
SocketServer server = new SocketServer();
|
16
16
|
ServerSessionRegistry sessionRegistry = new ServerSessionRegistry();
|
17
17
|
server.setHost(host);
|
@@ -21,6 +21,12 @@ public class EmbulkServer implements AutoCloseable {
|
|
21
21
|
server.registerSyncCommand(new InitializeSessionCommand(sessionRegistry));
|
22
22
|
server.registerSyncCommand(new RemoveSessionCommand(sessionRegistry));
|
23
23
|
server.registerCommand(new StartTaskCommand(sessionRegistry));
|
24
|
+
if (tlsConfig != null) {
|
25
|
+
server.setSslContext(tlsConfig.getSSLContext());
|
26
|
+
if (tlsConfig.isEnableClientAuth()) {
|
27
|
+
server.enableSslClientAuth();
|
28
|
+
}
|
29
|
+
}
|
24
30
|
server.start();
|
25
31
|
return new EmbulkServer(server);
|
26
32
|
}
|
@@ -12,13 +12,39 @@ public class Launcher {
|
|
12
12
|
Map<String, String> envVars = System.getenv();
|
13
13
|
String host = envVars.getOrDefault("BIND_ADDRESS", "0.0.0.0");
|
14
14
|
int port = Integer.parseInt(envVars.getOrDefault("PORT", "30001"));
|
15
|
-
int numOfWorkers = Integer.parseInt(envVars.getOrDefault("NUM_OF_WORKERS", "
|
16
|
-
|
17
|
-
configureLogLevel(
|
18
|
-
|
15
|
+
int numOfWorkers = Integer.parseInt(envVars.getOrDefault("NUM_OF_WORKERS", "5"));
|
16
|
+
TLSConfig tlsConfig = createTLSConfig(envVars);
|
17
|
+
configureLogLevel(envVars);
|
18
|
+
|
19
|
+
EmbulkServer.start(host, port, numOfWorkers, tlsConfig);
|
20
|
+
}
|
21
|
+
|
22
|
+
private static TLSConfig createTLSConfig(Map<String, String> envVars) {
|
23
|
+
if (!"true".equals(envVars.get("ENABLE_TLS"))) {
|
24
|
+
return null;
|
25
|
+
}
|
26
|
+
|
27
|
+
TLSConfig tlsConfig = new TLSConfig();
|
28
|
+
String keyP12Path = envVars.get("KEY_P12_PATH");
|
29
|
+
String keyP12Password = envVars.get("KEY_P12_PASSWORD");
|
30
|
+
if (keyP12Path != null && keyP12Password != null) {
|
31
|
+
tlsConfig.keyStore(new P12File(keyP12Path, keyP12Password));
|
32
|
+
}
|
33
|
+
|
34
|
+
String trustP12Path = envVars.get("TRUST_P12_PATH");
|
35
|
+
String trustP12Password = envVars.get("TRUST_P12_PASSWORD");
|
36
|
+
if (trustP12Path != null && trustP12Password != null) {
|
37
|
+
tlsConfig.trustStore(new P12File(trustP12Path, trustP12Password));
|
38
|
+
}
|
39
|
+
|
40
|
+
if ("true".equals(envVars.get("ENABLE_TLS_CLIENT_AUTH"))) {
|
41
|
+
tlsConfig.enableClientAuth(true);
|
42
|
+
}
|
43
|
+
return tlsConfig;
|
19
44
|
}
|
20
45
|
|
21
|
-
private static void configureLogLevel(
|
46
|
+
private static void configureLogLevel(Map<String, String> envVars) {
|
47
|
+
Level logLevel = Level.toLevel(envVars.getOrDefault("LOG_LEVEL", "info"));
|
22
48
|
Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
23
49
|
rootLogger.setLevel(logLevel);
|
24
50
|
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
package org.embulk.executor.remoteserver;
|
2
|
+
|
3
|
+
import com.fasterxml.jackson.annotation.JsonCreator;
|
4
|
+
import com.fasterxml.jackson.annotation.JsonProperty;
|
5
|
+
|
6
|
+
class P12File {
|
7
|
+
private final String path;
|
8
|
+
private final String password;
|
9
|
+
|
10
|
+
@JsonCreator
|
11
|
+
P12File(@JsonProperty("path") String path, @JsonProperty("password") String password) {
|
12
|
+
if (path == null || password == null) {
|
13
|
+
throw new NullPointerException("Path and password must not be null");
|
14
|
+
}
|
15
|
+
this.path = path;
|
16
|
+
this.password = password;
|
17
|
+
}
|
18
|
+
|
19
|
+
@JsonProperty
|
20
|
+
String getPath() {
|
21
|
+
return path;
|
22
|
+
}
|
23
|
+
|
24
|
+
@JsonProperty
|
25
|
+
String getPassword() {
|
26
|
+
return password;
|
27
|
+
}
|
28
|
+
}
|
@@ -24,6 +24,7 @@ import java.io.UncheckedIOException;
|
|
24
24
|
import java.nio.file.Files;
|
25
25
|
import java.util.Collections;
|
26
26
|
import java.util.List;
|
27
|
+
import java.util.Optional;
|
27
28
|
import java.util.concurrent.TimeoutException;
|
28
29
|
import java.util.stream.Collectors;
|
29
30
|
|
@@ -42,8 +43,33 @@ public class RemoteServerExecutor implements ExecutorPlugin {
|
|
42
43
|
@ConfigDefault("3600")
|
43
44
|
int getTimeoutSeconds();
|
44
45
|
|
46
|
+
@Config("tls")
|
47
|
+
@ConfigDefault("false")
|
48
|
+
boolean getTLS();
|
49
|
+
|
50
|
+
@Config("key_store_p12")
|
51
|
+
@ConfigDefault("null")
|
52
|
+
Optional<P12File> getKeyStoreP12();
|
53
|
+
|
54
|
+
@Config("trust_store_p12")
|
55
|
+
@ConfigDefault("null")
|
56
|
+
Optional<P12File> getTrustStoreP12();
|
57
|
+
|
45
58
|
@ConfigInject
|
46
59
|
ModelManager getModelManager();
|
60
|
+
|
61
|
+
// Used for the local mode (mainly for testing)
|
62
|
+
@Config("__server_key_store_p12")
|
63
|
+
@ConfigDefault("null")
|
64
|
+
Optional<P12File> getServerKeyStoreP12();
|
65
|
+
|
66
|
+
@Config("__server_trust_store_p12")
|
67
|
+
@ConfigDefault("null")
|
68
|
+
Optional<P12File> getServerTrustStoreP12();
|
69
|
+
|
70
|
+
@Config("__server_enable_client_auth")
|
71
|
+
@ConfigDefault("false")
|
72
|
+
boolean getServerEnableClientAuth();
|
47
73
|
}
|
48
74
|
|
49
75
|
@Inject
|
@@ -56,8 +82,8 @@ public class RemoteServerExecutor implements ExecutorPlugin {
|
|
56
82
|
public void transaction(ConfigSource config, Schema outputSchema, int inputTaskCount, Control control) {
|
57
83
|
PluginTask task = config.loadConfig(PluginTask.class);
|
58
84
|
if (task.getHosts().isEmpty()) {
|
59
|
-
log.info("Hosts is empty. Run
|
60
|
-
try (EmbulkServer _autoclosed =
|
85
|
+
log.info("Hosts is empty. Run as the local mode.");
|
86
|
+
try (EmbulkServer _autoclosed = startEmbulkServer(task)) {
|
61
87
|
control.transaction(outputSchema, inputTaskCount, new ExecutorImpl(inputTaskCount, task, Collections.singletonList(DEFAULT_HOST)));
|
62
88
|
} catch (IOException e) {
|
63
89
|
throw new UncheckedIOException(e);
|
@@ -103,7 +129,15 @@ public class RemoteServerExecutor implements ExecutorPlugin {
|
|
103
129
|
|
104
130
|
ClientSession session = new ClientSession(
|
105
131
|
systemConfigJson, pluginTaskJson, processTaskJson, gemSpecs, pluginArchiveBytes, state, inputTaskCount, modelManager);
|
106
|
-
|
132
|
+
|
133
|
+
TLSConfig tlsConfig = null;
|
134
|
+
if (pluginTask.getTLS()) {
|
135
|
+
tlsConfig = new TLSConfig();
|
136
|
+
pluginTask.getKeyStoreP12().ifPresent(tlsConfig::keyStore);
|
137
|
+
pluginTask.getTrustStoreP12().ifPresent(tlsConfig::trustStore);
|
138
|
+
}
|
139
|
+
|
140
|
+
try (EmbulkClient client = EmbulkClient.open(session, hosts, tlsConfig)) {
|
107
141
|
client.createSession();
|
108
142
|
|
109
143
|
state.initialize(inputTaskCount, inputTaskCount);
|
@@ -132,4 +166,17 @@ public class RemoteServerExecutor implements ExecutorPlugin {
|
|
132
166
|
}
|
133
167
|
}
|
134
168
|
}
|
169
|
+
|
170
|
+
private EmbulkServer startEmbulkServer(PluginTask task) throws IOException {
|
171
|
+
TLSConfig tlsConfig = null;
|
172
|
+
if (task.getTLS()) {
|
173
|
+
tlsConfig = new TLSConfig();
|
174
|
+
task.getServerKeyStoreP12().ifPresent(tlsConfig::keyStore);
|
175
|
+
task.getServerTrustStoreP12().ifPresent(tlsConfig::trustStore);
|
176
|
+
if (task.getServerEnableClientAuth()) {
|
177
|
+
tlsConfig.enableClientAuth(true);
|
178
|
+
}
|
179
|
+
}
|
180
|
+
return EmbulkServer.start(DEFAULT_HOST.getName(), DEFAULT_HOST.getPort(), 1, tlsConfig);
|
181
|
+
}
|
135
182
|
}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
package org.embulk.executor.remoteserver;
|
2
|
+
|
3
|
+
import javax.net.ssl.KeyManager;
|
4
|
+
import javax.net.ssl.KeyManagerFactory;
|
5
|
+
import javax.net.ssl.SSLContext;
|
6
|
+
import javax.net.ssl.TrustManager;
|
7
|
+
import javax.net.ssl.TrustManagerFactory;
|
8
|
+
import java.io.FileInputStream;
|
9
|
+
import java.io.InputStream;
|
10
|
+
import java.security.KeyStore;
|
11
|
+
|
12
|
+
class TLSConfig {
|
13
|
+
private P12File keyStore = null;
|
14
|
+
private P12File trustStore = null;
|
15
|
+
private boolean enableClientAuth = false;
|
16
|
+
|
17
|
+
TLSConfig() {
|
18
|
+
}
|
19
|
+
|
20
|
+
TLSConfig keyStore(P12File keyStore) {
|
21
|
+
this.keyStore = keyStore;
|
22
|
+
return this;
|
23
|
+
}
|
24
|
+
|
25
|
+
TLSConfig trustStore(P12File trustStore) {
|
26
|
+
this.trustStore = trustStore;
|
27
|
+
return this;
|
28
|
+
}
|
29
|
+
|
30
|
+
TLSConfig enableClientAuth(boolean enableClientAuth) {
|
31
|
+
this.enableClientAuth = enableClientAuth;
|
32
|
+
return this;
|
33
|
+
}
|
34
|
+
|
35
|
+
SSLContext getSSLContext() {
|
36
|
+
try {
|
37
|
+
KeyManager[] keyManagers = null;
|
38
|
+
if (keyStore != null) {
|
39
|
+
KeyStore ks = load(keyStore);
|
40
|
+
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
41
|
+
kmf.init(ks, keyStore.getPassword().toCharArray());
|
42
|
+
keyManagers = kmf.getKeyManagers();
|
43
|
+
}
|
44
|
+
|
45
|
+
TrustManager[] trustManagers = null;
|
46
|
+
if (trustStore != null) {
|
47
|
+
KeyStore ts = load(trustStore);
|
48
|
+
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
49
|
+
tmf.init(ts);
|
50
|
+
trustManagers = tmf.getTrustManagers();
|
51
|
+
}
|
52
|
+
|
53
|
+
SSLContext context = SSLContext.getInstance("TLS");
|
54
|
+
context.init(keyManagers, trustManagers, null);
|
55
|
+
return context;
|
56
|
+
} catch (Exception e) {
|
57
|
+
throw new RuntimeException(e);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
boolean isEnableClientAuth() {
|
62
|
+
return enableClientAuth;
|
63
|
+
}
|
64
|
+
|
65
|
+
private static KeyStore load(P12File file) {
|
66
|
+
try (InputStream keyStoreIS = new FileInputStream(file.getPath())) {
|
67
|
+
KeyStore ks = KeyStore.getInstance("PKCS12");
|
68
|
+
ks.load(keyStoreIS, file.getPassword().toCharArray());
|
69
|
+
return ks;
|
70
|
+
} catch (Exception e) {
|
71
|
+
throw new RuntimeException(e);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
@@ -3,6 +3,7 @@ package org.embulk.executor.remoteserver;
|
|
3
3
|
import org.embulk.config.ConfigSource;
|
4
4
|
import org.embulk.test.EmbulkPluginTest;
|
5
5
|
import org.embulk.test.EmbulkTest;
|
6
|
+
import org.junit.jupiter.api.BeforeEach;
|
6
7
|
import org.junit.jupiter.api.Test;
|
7
8
|
|
8
9
|
import java.io.File;
|
@@ -12,49 +13,65 @@ import java.nio.file.Files;
|
|
12
13
|
import java.nio.file.Path;
|
13
14
|
import java.nio.file.Paths;
|
14
15
|
import java.util.Arrays;
|
15
|
-
import java.util.Collections;
|
16
16
|
import java.util.HashSet;
|
17
|
-
import java.util.List;
|
18
17
|
import java.util.Set;
|
19
18
|
import java.util.stream.Collectors;
|
20
19
|
|
20
|
+
import static org.embulk.test.Utils.configFromResource;
|
21
21
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
22
22
|
|
23
23
|
@EmbulkTest(value = RemoteServerExecutor.class, name = "remoteserver")
|
24
24
|
class TestRemoteServerExecutor extends EmbulkPluginTest {
|
25
|
-
private static final List<String> HOSTS = Arrays.asList("localhost", "localhost:30002");
|
26
25
|
private static final Path OUTPUT_DIR = Paths.get("tmp", "output");
|
27
26
|
private static final Path TEST_DIR = Paths.get("test");
|
28
27
|
|
28
|
+
@BeforeEach
|
29
|
+
void cleanupOutputDir() {
|
30
|
+
File outputDir = OUTPUT_DIR.toFile();
|
31
|
+
if (outputDir.exists()) {
|
32
|
+
Arrays.stream(outputDir.listFiles()).forEach(File::delete);
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
29
36
|
@Test
|
30
37
|
void testSimpleCase() {
|
31
38
|
setSystemConfig(config().set("jruby_global_bundler_plugin_source_directory", TEST_DIR.toFile().getAbsolutePath()));
|
32
39
|
|
33
|
-
ConfigSource inConfig = config
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
.set("name", "a").set("type", "long")
|
38
|
-
))
|
39
|
-
);
|
40
|
+
ConfigSource inConfig = configFromResource("config/input.yml");
|
41
|
+
ConfigSource execConfig = configFromResource("config/exec_base.yml");
|
42
|
+
ConfigSource filterConfig = configFromResource("config/filter.yml");
|
43
|
+
ConfigSource outConfig = configFromResource("config/output.yml");
|
40
44
|
|
41
|
-
|
42
|
-
.
|
43
|
-
.
|
45
|
+
runConfig(inConfig)
|
46
|
+
.execConfig(execConfig)
|
47
|
+
.filterConfig(filterConfig)
|
48
|
+
.outConfig(outConfig).run();
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
50
|
+
File[] files = OUTPUT_DIR.toFile().listFiles();
|
51
|
+
assertEquals(2, files.length);
|
52
|
+
Set<String> outputs = Arrays.stream(files).map(f -> {
|
53
|
+
try {
|
54
|
+
return String.join("", Files.readAllLines(f.toPath()));
|
55
|
+
} catch (IOException e) {
|
56
|
+
throw new UncheckedIOException(e);
|
57
|
+
}
|
58
|
+
}).collect(Collectors.toSet());
|
59
|
+
|
60
|
+
Set<String> expected = new HashSet<String>(){{
|
61
|
+
add("c4ca4238a0b923820dcc509a6f75849b"); // "1" of MD5
|
62
|
+
add("c81e728d9d4c2f636f067f89cc14862c"); // "2" of MD5
|
63
|
+
}};
|
64
|
+
assertEquals(expected, outputs);
|
65
|
+
}
|
66
|
+
|
67
|
+
@Test
|
68
|
+
void testConnectWithTLS() {
|
69
|
+
setSystemConfig(config().set("jruby_global_bundler_plugin_source_directory", TEST_DIR.toFile().getAbsolutePath()));
|
49
70
|
|
50
|
-
ConfigSource
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
.set("type", "csv")
|
55
|
-
.set("header_line", false)
|
56
|
-
.set("quote_policy", "NONE")
|
57
|
-
);
|
71
|
+
ConfigSource inConfig = configFromResource("config/input.yml");
|
72
|
+
ConfigSource execConfig = configFromResource("config/exec_tls.yml");
|
73
|
+
ConfigSource filterConfig = configFromResource("config/filter.yml");
|
74
|
+
ConfigSource outConfig = configFromResource("config/output.yml");
|
58
75
|
|
59
76
|
runConfig(inConfig)
|
60
77
|
.execConfig(execConfig)
|
data/test/setup.sh
CHANGED
@@ -4,5 +4,11 @@ project_root="$(cd $(dirname $0)/..; pwd -P)"
|
|
4
4
|
cd ${project_root}
|
5
5
|
|
6
6
|
rm -rf tmp/output && mkdir -p tmp/output
|
7
|
+
rm -rf tmp/certs && mkdir -p tmp/certs
|
7
8
|
./gradlew embulk_bundle_--clean -Pgemfile=test/Gemfile -PbundlePath=${project_root}/tmp/vendor/bundle
|
8
|
-
|
9
|
+
|
10
|
+
if [[ "${SKIP_DOCKER_BUILD}" != "true" ]]; then
|
11
|
+
docker-compose -f docker-compose.test.yml build
|
12
|
+
fi
|
13
|
+
docker-compose -f docker-compose.test.yml run cert-generator
|
14
|
+
docker-compose -f docker-compose.test.yml up -d server1 server2 tls-server1 tls-server2
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: embulk-executor-remoteserver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shinichi Ishimura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-04-
|
11
|
+
date: 2019-04-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -51,12 +51,18 @@ files:
|
|
51
51
|
- LICENSE
|
52
52
|
- README.md
|
53
53
|
- build.gradle
|
54
|
-
- classpath/embulk-executor-remoteserver-0.
|
54
|
+
- classpath/embulk-executor-remoteserver-0.3.0.jar
|
55
55
|
- classpath/msgpack-core-0.8.16.jar
|
56
|
-
- classpath/nsocket-0.
|
56
|
+
- classpath/nsocket-0.3.4.jar
|
57
57
|
- classpath/slf4j-api-1.7.26.jar
|
58
|
-
- docker-compose.yml
|
58
|
+
- docker-compose.test.yml
|
59
59
|
- docker/run_embulk_server.sh
|
60
|
+
- example/Gemfile
|
61
|
+
- example/README.md
|
62
|
+
- example/config.yml
|
63
|
+
- example/docker-compse.yml
|
64
|
+
- example/work/input_1.json
|
65
|
+
- example/work/input_2.json
|
60
66
|
- gradle.properties
|
61
67
|
- gradle/dependency-locks/compileClasspath.lockfile
|
62
68
|
- gradle/dependency-locks/testCompileClasspath.lockfile
|
@@ -72,22 +78,28 @@ files:
|
|
72
78
|
- src/main/java/org/embulk/executor/remoteserver/Host.java
|
73
79
|
- src/main/java/org/embulk/executor/remoteserver/InitializeSessionCommand.java
|
74
80
|
- src/main/java/org/embulk/executor/remoteserver/Launcher.java
|
81
|
+
- src/main/java/org/embulk/executor/remoteserver/P12File.java
|
75
82
|
- src/main/java/org/embulk/executor/remoteserver/PluginArchive.java
|
76
83
|
- src/main/java/org/embulk/executor/remoteserver/RemoteServerExecutor.java
|
77
84
|
- src/main/java/org/embulk/executor/remoteserver/RemoveSessionCommand.java
|
78
85
|
- src/main/java/org/embulk/executor/remoteserver/ServerSession.java
|
79
86
|
- src/main/java/org/embulk/executor/remoteserver/ServerSessionRegistry.java
|
80
87
|
- src/main/java/org/embulk/executor/remoteserver/StartTaskCommand.java
|
88
|
+
- src/main/java/org/embulk/executor/remoteserver/TLSConfig.java
|
81
89
|
- src/main/java/org/embulk/executor/remoteserver/TaskExecutionException.java
|
82
90
|
- src/main/java/org/embulk/executor/remoteserver/TaskState.java
|
83
91
|
- src/main/java/org/embulk/executor/remoteserver/UpdateTaskStateCommand.java
|
84
92
|
- src/main/java/org/embulk/executor/remoteserver/UpdateTaskStateData.java
|
85
93
|
- src/main/resources/logback.xml
|
86
94
|
- src/test/java/org/embulk/executor/remoteserver/TestRemoteServerExecutor.java
|
95
|
+
- src/test/resources/config/exec_base.yml
|
96
|
+
- src/test/resources/config/exec_tls.yml
|
97
|
+
- src/test/resources/config/filter.yml
|
98
|
+
- src/test/resources/config/input.yml
|
99
|
+
- src/test/resources/config/output.yml
|
87
100
|
- src/test/resources/json/test1.json
|
88
101
|
- src/test/resources/json/test2.json
|
89
102
|
- test/Gemfile
|
90
|
-
- test/Gemfile.lock
|
91
103
|
- test/setup.sh
|
92
104
|
homepage: https://github.com/kamatama41/embulk-executor-remoteserver
|
93
105
|
licenses:
|
@@ -115,5 +127,4 @@ specification_version: 4
|
|
115
127
|
summary: Docker executor plugin for Embulk
|
116
128
|
test_files:
|
117
129
|
- test/Gemfile
|
118
|
-
- test/Gemfile.lock
|
119
130
|
- test/setup.sh
|
data/docker-compose.yml
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
version: '3.2'
|
2
|
-
services:
|
3
|
-
server1:
|
4
|
-
build:
|
5
|
-
context: .
|
6
|
-
dockerfile: Dockerfile
|
7
|
-
environment:
|
8
|
-
LOG_LEVEL: debug
|
9
|
-
ports:
|
10
|
-
- "30001:30001"
|
11
|
-
volumes:
|
12
|
-
- ./tmp/output:/output
|
13
|
-
- ./src/test/resources/json:/root/src/test/resources/json
|
14
|
-
server2:
|
15
|
-
build:
|
16
|
-
context: .
|
17
|
-
dockerfile: Dockerfile
|
18
|
-
environment:
|
19
|
-
LOG_LEVEL: debug
|
20
|
-
ports:
|
21
|
-
- "30002:30001"
|
22
|
-
volumes:
|
23
|
-
- ./tmp/output:/output
|
24
|
-
- ./src/test/resources/json:/root/src/test/resources/json
|
data/test/Gemfile.lock
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
GEM
|
2
|
-
remote: https://rubygems.org/
|
3
|
-
specs:
|
4
|
-
embulk (0.9.16-java)
|
5
|
-
bundler (>= 1.10.6)
|
6
|
-
liquid (~> 4.0.0)
|
7
|
-
msgpack (~> 1.1.0)
|
8
|
-
embulk-filter-hash (0.5.0)
|
9
|
-
liquid (4.0.0)
|
10
|
-
msgpack (1.1.0-java)
|
11
|
-
|
12
|
-
PLATFORMS
|
13
|
-
java
|
14
|
-
|
15
|
-
DEPENDENCIES
|
16
|
-
embulk
|
17
|
-
embulk-filter-hash (= 0.5.0)
|
18
|
-
|
19
|
-
BUNDLED WITH
|
20
|
-
1.16.0
|