embulk-executor-remoteserver 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|