embulk-input-remote 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embulk-input-remote
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.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: 2017-01-22 00:00:00.000000000 Z
11
+ date: 2017-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -52,29 +52,28 @@ files:
52
52
  - README.md
53
53
  - build.gradle
54
54
  - docker-compose.yml
55
- - example/csv/sample_01.csv.gz
56
- - example/example.yml.liquid
57
55
  - gradle/wrapper/gradle-wrapper.jar
58
56
  - gradle/wrapper/gradle-wrapper.properties
59
57
  - gradlew
60
58
  - gradlew.bat
61
59
  - lib/embulk/input/remote.rb
62
- - src/main/java/org/embulk/input/RemoteFileInputPlugin.java
63
- - src/main/java/org/embulk/input/remote/SSHClient.java
64
- - src/test/java/org/embulk/input/TestRemoteFileInputPlugin.java
65
- - src/test/java/org/embulk/test/MemoryOutputPlugin.java
66
- - src/test/java/org/embulk/test/MyEmbulkTests.java
67
- - src/test/java/org/embulk/test/MyTestingEmbulk.java
60
+ - settings.gradle
61
+ - src/main/kotlin/org/embulk/input/RemoteFileInputPlugin.kt
62
+ - src/main/kotlin/org/embulk/input/remote/SSHClient.kt
63
+ - src/test/kotlin/org/embulk/input/TestRemoteFileInputPlugin.kt
68
64
  - src/test/resources/input/host1/test.csv
69
65
  - src/test/resources/input/host1/test_command.csv
70
66
  - src/test/resources/input/host2/test.csv
71
67
  - src/test/resources/input/host2/test_command.csv
68
+ - src/test/resources/script/hosts.sh
72
69
  - src/test/resources/yaml/base.yml
73
70
  - classpath/bcpkix-jdk15on-1.51.jar
74
71
  - classpath/bcprov-jdk15on-1.51.jar
75
72
  - classpath/eddsa-0.1.0.jar
76
- - classpath/embulk-input-remote-0.2.0.jar
73
+ - classpath/embulk-input-remote-0.3.0.jar
77
74
  - classpath/jzlib-1.1.3.jar
75
+ - classpath/kotlin-runtime-1.0.6.jar
76
+ - classpath/kotlin-stdlib-1.0.6.jar
78
77
  - classpath/sshj-0.19.1.jar
79
78
  homepage: https://github.com/kamatama41/embulk-input-remote
80
79
  licenses:
Binary file
@@ -1,29 +0,0 @@
1
- in:
2
- type: remote
3
- hosts:
4
- - localhost
5
- path: {{ env.PROJECT_ROOT }}/example/csv
6
- ignore_not_found_hosts: true
7
- auth:
8
- user: {{ env.USER }}
9
- type: password
10
- password: {{ env.PASSWORD }}
11
- decoders:
12
- - {type: gzip}
13
- parser:
14
- charset: UTF-8
15
- newline: CRLF
16
- type: csv
17
- delimiter: ','
18
- quote: '"'
19
- trim_if_not_quoted: false
20
- skip_header_lines: 1
21
- allow_extra_columns: false
22
- allow_optional_columns: false
23
- columns:
24
- - {name: id, type: long}
25
- - {name: account, type: long}
26
- - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
27
- - {name: purchase, type: timestamp, format: '%Y%m%d'}
28
- - {name: comment, type: string}
29
- out: {type: stdout}
@@ -1,314 +0,0 @@
1
- package org.embulk.input;
2
-
3
- import java.io.BufferedReader;
4
- import java.io.ByteArrayInputStream;
5
- import java.io.ByteArrayOutputStream;
6
- import java.io.IOException;
7
- import java.io.InputStream;
8
- import java.io.InputStreamReader;
9
- import java.util.ArrayList;
10
- import java.util.Arrays;
11
- import java.util.List;
12
- import java.util.Objects;
13
-
14
- import com.fasterxml.jackson.annotation.JsonCreator;
15
- import com.fasterxml.jackson.annotation.JsonProperty;
16
- import com.google.common.base.Optional;
17
- import com.google.common.collect.ImmutableList;
18
- import org.embulk.config.Config;
19
- import org.embulk.config.ConfigDefault;
20
- import org.embulk.config.ConfigDiff;
21
- import org.embulk.config.ConfigInject;
22
- import org.embulk.config.ConfigSource;
23
- import org.embulk.config.Task;
24
- import org.embulk.config.TaskReport;
25
- import org.embulk.config.TaskSource;
26
- import org.embulk.input.remote.SSHClient;
27
- import org.embulk.spi.BufferAllocator;
28
- import org.embulk.spi.Exec;
29
- import org.embulk.spi.FileInputPlugin;
30
- import org.embulk.spi.TransactionalFileInput;
31
- import org.embulk.spi.util.InputStreamTransactionalFileInput;
32
- import org.slf4j.Logger;
33
-
34
- public class RemoteFileInputPlugin
35
- implements FileInputPlugin {
36
- public interface PluginTask
37
- extends Task {
38
- @Config("hosts")
39
- @ConfigDefault("[]")
40
- List<String> getHosts();
41
-
42
- @Config("hosts_command")
43
- @ConfigDefault("null")
44
- Optional<String> getHostsCommand();
45
-
46
- @Config("hosts_separator")
47
- @ConfigDefault("\" \"")
48
- String getHostsSeparator();
49
-
50
- @Config("default_port")
51
- @ConfigDefault("22")
52
- int getDefaultPort();
53
-
54
- @Config("path")
55
- @ConfigDefault("\"\"")
56
- String getPath();
57
-
58
- @Config("path_command")
59
- @ConfigDefault("null")
60
- Optional<String> getPathCommand();
61
-
62
- @Config("auth")
63
- AuthConfig getAuthConfig();
64
-
65
- @Config("ignore_not_found_hosts")
66
- @ConfigDefault("false")
67
- boolean getIgnoreNotFoundHosts();
68
-
69
- @Config("done_targets")
70
- @ConfigDefault("[]")
71
- List<Target> getDoneTargets();
72
-
73
- void setDoneTargets(List<Target> lastTarget);
74
-
75
- List<Target> getTargets();
76
-
77
- void setTargets(List<Target> targets);
78
-
79
- @ConfigInject
80
- BufferAllocator getBufferAllocator();
81
- }
82
-
83
- public interface AuthConfig extends Task {
84
- @Config("type")
85
- @ConfigDefault("\"public_key\"")
86
- String getType();
87
-
88
- @Config("user")
89
- @ConfigDefault("null")
90
- Optional<String> getUser();
91
-
92
- @Config("key_path")
93
- @ConfigDefault("null")
94
- Optional<String> getKeyPath();
95
-
96
- @Config("password")
97
- @ConfigDefault("null")
98
- Optional<String> getPassword();
99
-
100
- @Config("skip_host_key_verification")
101
- @ConfigDefault("false")
102
- boolean getSkipHostKeyVerification();
103
- }
104
-
105
- private final Logger log = Exec.getLogger(getClass());
106
-
107
- @Override
108
- public ConfigDiff transaction(ConfigSource config, FileInputPlugin.Control control) {
109
- PluginTask task = config.loadConfig(PluginTask.class);
110
- List<Target> targets = listTargets(task);
111
- log.info("Loading targets {}", targets);
112
- task.setTargets(targets);
113
-
114
- // number of processors is same with number of targets
115
- int taskCount = targets.size();
116
- return resume(task.dump(), taskCount, control);
117
- }
118
-
119
- private List<Target> listTargets(PluginTask task) {
120
- final List<String> hosts = listHosts(task);
121
- final String path = getPath(task);
122
-
123
- final ImmutableList.Builder<Target> builder = ImmutableList.builder();
124
- List<Target> doneTargets = task.getDoneTargets();
125
- for (String host : hosts) {
126
- String[] split = host.split(":");
127
- final String targetHost = split[0];
128
- int targetPort = task.getDefaultPort();
129
- if (split.length > 1) {
130
- targetPort = Integer.valueOf(split[1]);
131
- }
132
- Target target = new Target(targetHost, targetPort, path);
133
-
134
- if (!doneTargets.contains(target)) {
135
- if (task.getIgnoreNotFoundHosts()) {
136
- try {
137
- final boolean exists = exists(target, task);
138
- if (!exists) {
139
- continue;
140
- }
141
- } catch (IOException e) {
142
- log.warn("failed to check the file exists. " + target.toString(), e);
143
- continue;
144
- }
145
- }
146
- builder.add(target);
147
- }
148
- }
149
- return builder.build();
150
- }
151
-
152
- private List<String> listHosts(PluginTask task) {
153
- final String hostsCommand = task.getHostsCommand().orNull();
154
- if (hostsCommand != null) {
155
- final String stdout = execCommand(hostsCommand).trim();
156
- return Arrays.asList(stdout.split(task.getHostsSeparator()));
157
- } else {
158
- return task.getHosts();
159
- }
160
- }
161
-
162
- private String getPath(PluginTask task) {
163
- final String pathCommand = task.getPathCommand().orNull();
164
- if (pathCommand != null) {
165
- return execCommand(pathCommand).trim();
166
- } else {
167
- return task.getPath();
168
- }
169
- }
170
-
171
- private String execCommand(String command) {
172
- ProcessBuilder pb = new ProcessBuilder("sh", "-c", command); // TODO: windows
173
- log.info("Running command {}", command);
174
- try {
175
- final Process process = pb.start();
176
- try (InputStream stream = process.getInputStream();
177
- BufferedReader brStdout = new BufferedReader(new InputStreamReader(stream))
178
- ) {
179
- String line;
180
- StringBuilder stdout = new StringBuilder();
181
- while ((line = brStdout.readLine()) != null) {
182
- stdout.append(line);
183
- }
184
-
185
- final int code = process.waitFor();
186
- if (code != 0) {
187
- throw new IOException(String.format(
188
- "Command finished with non-zero exit code. Exit code is %d.", code));
189
- }
190
-
191
- return stdout.toString();
192
- }
193
- } catch (IOException | InterruptedException e) {
194
- throw new RuntimeException(e);
195
- }
196
- }
197
-
198
- @Override
199
- public ConfigDiff resume(TaskSource taskSource,
200
- int taskCount,
201
- FileInputPlugin.Control control) {
202
- PluginTask task = taskSource.loadTask(PluginTask.class);
203
-
204
- control.run(taskSource, taskCount);
205
-
206
- List<Target> targets = new ArrayList<>(task.getTargets());
207
-
208
- return Exec.newConfigDiff().set("done_targets", targets);
209
- }
210
-
211
- @Override
212
- public void cleanup(TaskSource taskSource,
213
- int taskCount,
214
- List<TaskReport> successTaskReports) {
215
- }
216
-
217
- @Override
218
- public TransactionalFileInput open(TaskSource taskSource, int taskIndex) {
219
- final PluginTask task = taskSource.loadTask(PluginTask.class);
220
- final Target target = task.getTargets().get(taskIndex);
221
-
222
- return new InputStreamTransactionalFileInput(
223
- task.getBufferAllocator(),
224
- new InputStreamTransactionalFileInput.Opener() {
225
- @Override
226
- public InputStream open() throws IOException {
227
- return download(target, task);
228
- }
229
- }
230
- ) {
231
- @Override
232
- public void abort() {
233
-
234
- }
235
-
236
- @Override
237
- public TaskReport commit() {
238
- return Exec.newTaskReport();
239
- }
240
- };
241
- }
242
-
243
- private boolean exists(Target target, PluginTask task) throws IOException {
244
- try (SSHClient client = SSHClient.connect(target.getHost(), target.getPort(), task.getAuthConfig())) {
245
- final String checkCmd = "ls " + target.getPath(); // TODO: windows
246
- final int timeout = 5/* second */;
247
- final SSHClient.CommandResult commandResult = client.execCommand(checkCmd, timeout);
248
-
249
- if(commandResult.getStatus() != 0) {
250
- log.warn("Remote file not found. {}", target.toString());
251
- return false;
252
- } else {
253
- return true;
254
- }
255
- }
256
- }
257
-
258
- private InputStream download(Target target, PluginTask task) throws IOException {
259
- try (SSHClient client = SSHClient.connect(target.getHost(), target.getPort(), task.getAuthConfig())) {
260
- final ByteArrayOutputStream stream = new ByteArrayOutputStream();
261
- client.scpDownload(target.getPath(), stream);
262
- return new ByteArrayInputStream(stream.toByteArray());
263
- }
264
- }
265
-
266
- public static class Target {
267
- private final String host;
268
- private final int port;
269
- private final String path;
270
-
271
- @JsonCreator
272
- public Target(
273
- @JsonProperty("host") String host,
274
- @JsonProperty("port") int port,
275
- @JsonProperty("path") String path
276
- ) {
277
- this.host = host;
278
- this.port = port;
279
- this.path = path;
280
- }
281
-
282
- public String getHost() {
283
- return host;
284
- }
285
-
286
- public int getPort() {
287
- return port;
288
- }
289
-
290
- public String getPath() {
291
- return path;
292
- }
293
-
294
- @Override
295
- public boolean equals(Object o) {
296
- if (this == o) return true;
297
- if (o == null || getClass() != o.getClass()) return false;
298
- Target target = (Target) o;
299
- return port == target.port &&
300
- Objects.equals(host, target.host) &&
301
- Objects.equals(path, target.path);
302
- }
303
-
304
- @Override
305
- public int hashCode() {
306
- return Objects.hash(host, port, path);
307
- }
308
-
309
- @Override
310
- public String toString() {
311
- return host + ":" + port + ":" + path;
312
- }
313
- }
314
- }
@@ -1,116 +0,0 @@
1
- package org.embulk.input.remote;
2
-
3
- import net.schmizz.sshj.DefaultConfig;
4
- import net.schmizz.sshj.connection.channel.direct.Session;
5
- import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
6
- import net.schmizz.sshj.xfer.InMemoryDestFile;
7
- import net.schmizz.sshj.xfer.LocalDestFile;
8
- import org.embulk.input.RemoteFileInputPlugin;
9
-
10
- import java.io.Closeable;
11
- import java.io.IOException;
12
- import java.io.InputStream;
13
- import java.io.OutputStream;
14
- import java.util.concurrent.TimeUnit;
15
-
16
- public class SSHClient implements Closeable {
17
-
18
- private final net.schmizz.sshj.SSHClient client;
19
-
20
- public static SSHClient connect(
21
- String host, int port, RemoteFileInputPlugin.AuthConfig authConfig
22
- ) throws IOException {
23
-
24
- SSHClient client = new SSHClient(new net.schmizz.sshj.SSHClient(new DefaultConfig()));
25
- client.connectToHost(host, port, authConfig);
26
- return client;
27
- }
28
-
29
- private SSHClient(net.schmizz.sshj.SSHClient client) {
30
- this.client = client;
31
- }
32
-
33
- private void connectToHost(String host, int port, RemoteFileInputPlugin.AuthConfig authConfig) throws IOException {
34
- if (authConfig.getSkipHostKeyVerification()) {
35
- client.addHostKeyVerifier(new PromiscuousVerifier());
36
- }
37
- client.loadKnownHosts();
38
- client.connect(host, port);
39
-
40
- final String type = authConfig.getType();
41
- final String user = authConfig.getUser().or(System.getProperty("user.name"));
42
-
43
- if ("password".equals(type)) {
44
- if (authConfig.getPassword().isPresent()) {
45
- client.authPassword(user, authConfig.getPassword().get());
46
- } else {
47
- throw new IllegalStateException("Password is not set.");
48
- }
49
- } else if ("public_key".equals(type)) {
50
- if (authConfig.getKeyPath().isPresent()) {
51
- client.authPublickey(user, authConfig.getKeyPath().get());
52
- } else {
53
- client.authPublickey(user);
54
- }
55
- } else {
56
- throw new UnsupportedOperationException("Unsupported auth type : " + type);
57
- }
58
- }
59
-
60
- public CommandResult execCommand(String command, int timeoutSecond) throws IOException {
61
- try (final Session session = client.startSession()) {
62
- final Session.Command cmd = session.exec(command);
63
- cmd.join(timeoutSecond, TimeUnit.SECONDS);
64
- return new CommandResult(cmd.getExitStatus(), cmd.getInputStream());
65
- }
66
- }
67
-
68
- public void scpDownload(String path, OutputStream stream) throws IOException {
69
- client.useCompression();
70
- client.newSCPFileTransfer().download(path, new InMemoryDestFileImpl(stream));
71
- }
72
-
73
- private static class InMemoryDestFileImpl extends InMemoryDestFile {
74
-
75
- private OutputStream outputStream;
76
-
77
- public InMemoryDestFileImpl(OutputStream outputStream) {
78
- this.outputStream = outputStream;
79
- }
80
-
81
- @Override
82
- public OutputStream getOutputStream() throws IOException {
83
- return outputStream;
84
- }
85
-
86
- @Override
87
- public LocalDestFile getTargetDirectory(String dirname) throws IOException {
88
- return this;
89
- }
90
- }
91
-
92
- @Override
93
- public void close() throws IOException {
94
- if (client != null) {
95
- client.close();
96
- }
97
- }
98
-
99
- public static class CommandResult {
100
- int status;
101
- InputStream stdout;
102
-
103
- private CommandResult(int status, InputStream stdout) {
104
- this.status = status;
105
- this.stdout = stdout;
106
- }
107
-
108
- public int getStatus() {
109
- return status;
110
- }
111
-
112
- public InputStream getStdout() {
113
- return stdout;
114
- }
115
- }
116
- }