embulk-output-gcs 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +25 -0
- data/build.gradle +3 -3
- data/classpath/embulk-output-gcs-0.2.0.jar +0 -0
- data/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/gradle/wrapper/gradle-wrapper.properties +2 -2
- data/src/main/java/org/embulk/output/GcsAuthentication.java +96 -0
- data/src/main/java/org/embulk/output/GcsOutputPlugin.java +44 -47
- metadata +4 -3
- data/classpath/embulk-output-gcs-0.1.1.jar +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 94fccd956be721058fbf74ffd57017d05caf8e5b
|
4
|
+
data.tar.gz: e7e35ef7704225a633d47babdd21c91edd6ad272
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b2325cf0230d16f57fb7a247a9237428fd2d4527cd6848367a5989e3d8bc9a9da7f282b3a81ec97ad2425da9bb70cbd0a26465fcc1dd747ce3e804908cd48ad
|
7
|
+
data.tar.gz: ceb4828ba593c2e2ab8cf043bce26b4509867489cf3b7eac96fd00f1ef10b5ffe8895587a1844d7b01671ea0373cd30b82d39a94da2caf8183cdee206dcdd4e7
|
data/README.md
CHANGED
@@ -15,6 +15,7 @@ Google Cloud Storage output plugin for [Embulk](https://github.com/embulk/embulk
|
|
15
15
|
- **path_prefix**: Prefix of output keys (string, required)
|
16
16
|
- **file_ext**: Extention of output file (string, required)
|
17
17
|
- **content_type**: content type of output file (string, optional, default value is "application/octet-stream")
|
18
|
+
- **auth_method**: Authentication method `private_key` or `compute_engine` (string, optional, default value is "private_key")
|
18
19
|
- **service_account_email**: Google Cloud Platform service account email (string, required)
|
19
20
|
- **p12_keyfile_path**: Private key file fullpath of Google Cloud Platform service account (string, required)
|
20
21
|
- **application_name**: Application name, anything you like (string, optional, default value is "embulk-output-gcs")
|
@@ -27,6 +28,7 @@ out:
|
|
27
28
|
bucket: your-gcs-bucket-name
|
28
29
|
path_prefix: logs/out
|
29
30
|
file_ext: .csv
|
31
|
+
auth_method: `private_key` #default
|
30
32
|
service_account_email: 'XYZ@developer.gserviceaccount.com'
|
31
33
|
p12_keyfile_path: '/path/to/private/key.p12'
|
32
34
|
formatter:
|
@@ -34,6 +36,29 @@ out:
|
|
34
36
|
encoding: UTF-8
|
35
37
|
```
|
36
38
|
|
39
|
+
## Authentication
|
40
|
+
|
41
|
+
There are two methods supported to fetch access token for the service account.
|
42
|
+
|
43
|
+
1. Public-Private key pair
|
44
|
+
2. Pre-defined access token (Compute Engine only)
|
45
|
+
|
46
|
+
The examples above use the first one. You first need to create a service account (client ID),
|
47
|
+
download its private key and deploy the key with embulk.
|
48
|
+
|
49
|
+
On the other hand, you don't need to explicitly create a service account for embulk when you
|
50
|
+
run embulk in Google Compute Engine. In this second authentication method, you need to
|
51
|
+
add the API scope "https://www.googleapis.com/auth/devstorage.read_write" to the scope list of your
|
52
|
+
Compute Engine instance, then you can configure embulk like this.
|
53
|
+
|
54
|
+
[Setting the scope of service account access for instances](https://cloud.google.com/compute/docs/authentication)
|
55
|
+
|
56
|
+
```yaml
|
57
|
+
out:
|
58
|
+
type: gcs
|
59
|
+
auth_method: compute_engine
|
60
|
+
```
|
61
|
+
|
37
62
|
## Build
|
38
63
|
|
39
64
|
```
|
data/build.gradle
CHANGED
@@ -15,11 +15,11 @@ configurations {
|
|
15
15
|
sourceCompatibility = 1.7
|
16
16
|
targetCompatibility = 1.7
|
17
17
|
|
18
|
-
version = "0.
|
18
|
+
version = "0.2.0"
|
19
19
|
|
20
20
|
dependencies {
|
21
|
-
compile "org.embulk:embulk-core:0.
|
22
|
-
provided "org.embulk:embulk-core:0.
|
21
|
+
compile "org.embulk:embulk-core:0.7.3"
|
22
|
+
provided "org.embulk:embulk-core:0.7.3"
|
23
23
|
|
24
24
|
compile "com.google.http-client:google-http-client-jackson2:1.19.0"
|
25
25
|
compile ("com.google.apis:google-api-services-storage:v1-rev28-1.19.1") {exclude module: "guava-jdk5"}
|
Binary file
|
Binary file
|
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
#Tue Aug 11 00:26:20 PDT 2015
|
2
2
|
distributionBase=GRADLE_USER_HOME
|
3
3
|
distributionPath=wrapper/dists
|
4
4
|
zipStoreBase=GRADLE_USER_HOME
|
5
5
|
zipStorePath=wrapper/dists
|
6
|
-
distributionUrl=https\://services.gradle.org/distributions/gradle-2.
|
6
|
+
distributionUrl=https\://services.gradle.org/distributions/gradle-2.6-bin.zip
|
@@ -0,0 +1,96 @@
|
|
1
|
+
package org.embulk.output;
|
2
|
+
|
3
|
+
import java.io.File;
|
4
|
+
import java.io.IOException;
|
5
|
+
|
6
|
+
import com.google.api.client.http.apache.ApacheHttpTransport;
|
7
|
+
import com.google.api.services.storage.model.Objects;
|
8
|
+
import com.google.common.base.Optional;
|
9
|
+
import com.google.common.collect.ImmutableList;
|
10
|
+
import java.security.GeneralSecurityException;
|
11
|
+
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
12
|
+
import com.google.api.client.googleapis.compute.ComputeCredential;
|
13
|
+
import com.google.api.client.http.HttpTransport;
|
14
|
+
import com.google.api.client.json.JsonFactory;
|
15
|
+
import com.google.api.client.json.jackson2.JacksonFactory;
|
16
|
+
import com.google.api.client.http.HttpRequestInitializer;
|
17
|
+
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
|
18
|
+
import com.google.api.services.storage.Storage;
|
19
|
+
import com.google.api.services.storage.StorageScopes;
|
20
|
+
import org.embulk.spi.Exec;
|
21
|
+
import org.slf4j.Logger;
|
22
|
+
|
23
|
+
public class GcsAuthentication
|
24
|
+
{
|
25
|
+
private final Logger log = Exec.getLogger(GcsAuthentication.class);
|
26
|
+
private final Optional<String> serviceAccountEmail;
|
27
|
+
private final Optional<String> p12KeyFilePath;
|
28
|
+
private final String applicationName;
|
29
|
+
private final HttpTransport httpTransport;
|
30
|
+
private final JsonFactory jsonFactory;
|
31
|
+
private final HttpRequestInitializer credentials;
|
32
|
+
|
33
|
+
public GcsAuthentication(String authMethod, Optional<String> serviceAccountEmail, Optional<String> p12KeyFilePath, String applicationName)
|
34
|
+
throws IOException, GeneralSecurityException
|
35
|
+
{
|
36
|
+
this.serviceAccountEmail = serviceAccountEmail;
|
37
|
+
this.p12KeyFilePath = p12KeyFilePath;
|
38
|
+
this.applicationName = applicationName;
|
39
|
+
|
40
|
+
this.httpTransport = new ApacheHttpTransport.Builder().build();
|
41
|
+
this.jsonFactory = new JacksonFactory();
|
42
|
+
|
43
|
+
if (authMethod.equals("compute_engine")) {
|
44
|
+
this.credentials = getComputeCredential();
|
45
|
+
} else {
|
46
|
+
this.credentials = getServiceAccountCredential();
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
/**
|
51
|
+
* @see https://developers.google.com/accounts/docs/OAuth2ServiceAccount#authorizingrequests
|
52
|
+
*/
|
53
|
+
private GoogleCredential getServiceAccountCredential() throws IOException, GeneralSecurityException
|
54
|
+
{
|
55
|
+
// @see https://cloud.google.com/compute/docs/api/how-tos/authorization
|
56
|
+
// @see https://developers.google.com/resources/api-libraries/documentation/storage/v1/java/latest/com/google/api/services/storage/STORAGE_SCOPE.html
|
57
|
+
// @see https://developers.google.com/resources/api-libraries/documentation/bigquery/v2/java/latest/com/google/api/services/bigquery/BigqueryScopes.html
|
58
|
+
return new GoogleCredential.Builder()
|
59
|
+
.setTransport(httpTransport)
|
60
|
+
.setJsonFactory(jsonFactory)
|
61
|
+
.setServiceAccountId(serviceAccountEmail.orNull())
|
62
|
+
.setServiceAccountScopes(
|
63
|
+
ImmutableList.of(
|
64
|
+
StorageScopes.DEVSTORAGE_READ_WRITE
|
65
|
+
)
|
66
|
+
)
|
67
|
+
.setServiceAccountPrivateKeyFromP12File(new File(p12KeyFilePath.orNull()))
|
68
|
+
.build();
|
69
|
+
}
|
70
|
+
|
71
|
+
/**
|
72
|
+
* @see http://developers.guge.io/accounts/docs/OAuth2ServiceAccount#creatinganaccount
|
73
|
+
* @see https://developers.google.com/accounts/docs/OAuth2
|
74
|
+
*/
|
75
|
+
private ComputeCredential getComputeCredential() throws IOException
|
76
|
+
{
|
77
|
+
ComputeCredential credential = new ComputeCredential.Builder(httpTransport, jsonFactory)
|
78
|
+
.build();
|
79
|
+
credential.refreshToken();
|
80
|
+
|
81
|
+
return credential;
|
82
|
+
}
|
83
|
+
|
84
|
+
public Storage getGcsClient(String bucket) throws GoogleJsonResponseException, IOException
|
85
|
+
{
|
86
|
+
Storage client = new Storage.Builder(httpTransport, jsonFactory, credentials)
|
87
|
+
.setApplicationName(applicationName)
|
88
|
+
.build();
|
89
|
+
|
90
|
+
// For throw IOException when authentication is fail.
|
91
|
+
long maxResults = 1;
|
92
|
+
Objects objects = client.objects().list(bucket).setMaxResults(maxResults).execute();
|
93
|
+
|
94
|
+
return client;
|
95
|
+
}
|
96
|
+
}
|
@@ -1,22 +1,16 @@
|
|
1
1
|
package org.embulk.output;
|
2
2
|
|
3
|
-
import com.google.api.client.auth.oauth2.Credential;
|
4
|
-
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
5
|
-
import com.google.api.client.http.HttpTransport;
|
6
3
|
import com.google.api.client.http.InputStreamContent;
|
7
|
-
import com.google.api.client.http.apache.ApacheHttpTransport;
|
8
|
-
import com.google.api.client.json.JsonFactory;
|
9
|
-
import com.google.api.client.json.jackson2.JacksonFactory;
|
10
4
|
import com.google.api.services.storage.Storage;
|
11
|
-
import com.google.api.services.storage.StorageScopes;
|
12
5
|
import com.google.api.services.storage.model.StorageObject;
|
6
|
+
import com.google.common.base.Optional;
|
13
7
|
import com.google.common.base.Throwables;
|
14
|
-
import
|
15
|
-
import org.embulk.config.CommitReport;
|
8
|
+
import org.embulk.config.TaskReport;
|
16
9
|
import org.embulk.config.Config;
|
17
10
|
import org.embulk.config.ConfigDefault;
|
18
11
|
import org.embulk.config.ConfigDiff;
|
19
12
|
import org.embulk.config.ConfigSource;
|
13
|
+
import org.embulk.config.ConfigException;
|
20
14
|
import org.embulk.config.Task;
|
21
15
|
import org.embulk.config.TaskSource;
|
22
16
|
import org.embulk.spi.Buffer;
|
@@ -25,7 +19,6 @@ import org.embulk.spi.FileOutputPlugin;
|
|
25
19
|
import org.embulk.spi.TransactionalFileOutput;
|
26
20
|
import org.slf4j.Logger;
|
27
21
|
|
28
|
-
import java.io.File;
|
29
22
|
import java.io.IOException;
|
30
23
|
import java.io.PipedInputStream;
|
31
24
|
import java.io.PipedOutputStream;
|
@@ -40,35 +33,40 @@ import java.util.concurrent.Future;
|
|
40
33
|
|
41
34
|
public class GcsOutputPlugin implements FileOutputPlugin {
|
42
35
|
private static final Logger logger = Exec.getLogger(GcsOutputPlugin.class);
|
43
|
-
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
|
44
36
|
|
45
37
|
public interface PluginTask extends Task {
|
46
38
|
@Config("bucket")
|
47
|
-
|
39
|
+
String getBucket();
|
48
40
|
|
49
41
|
@Config("path_prefix")
|
50
|
-
|
42
|
+
String getPathPrefix();
|
51
43
|
|
52
44
|
@Config("file_ext")
|
53
|
-
|
45
|
+
String getFileNameExtension();
|
54
46
|
|
55
47
|
@Config("sequence_format")
|
56
48
|
@ConfigDefault("\".%03d.%02d\"")
|
57
|
-
|
49
|
+
String getSequenceFormat();
|
58
50
|
|
59
51
|
@Config("content_type")
|
60
52
|
@ConfigDefault("\"application/octet-stream\"")
|
61
|
-
|
53
|
+
String getContentType();
|
54
|
+
|
55
|
+
@Config("auth_method")
|
56
|
+
@ConfigDefault("\"private_key\"")
|
57
|
+
AuthMethod getAuthMethod();
|
62
58
|
|
63
59
|
@Config("service_account_email")
|
64
|
-
|
60
|
+
@ConfigDefault("null")
|
61
|
+
Optional<String> getServiceAccountEmail();
|
65
62
|
|
66
63
|
@Config("p12_keyfile_path")
|
67
|
-
|
64
|
+
@ConfigDefault("null")
|
65
|
+
Optional<String> getP12KeyfilePath();
|
68
66
|
|
69
67
|
@Config("application_name")
|
70
68
|
@ConfigDefault("\"embulk-output-gcs\"")
|
71
|
-
|
69
|
+
String getApplicationName();
|
72
70
|
}
|
73
71
|
|
74
72
|
@Override
|
@@ -90,7 +88,7 @@ public class GcsOutputPlugin implements FileOutputPlugin {
|
|
90
88
|
@Override
|
91
89
|
public void cleanup(TaskSource taskSource,
|
92
90
|
int taskCount,
|
93
|
-
List<
|
91
|
+
List<TaskReport> successTaskReports) {
|
94
92
|
}
|
95
93
|
|
96
94
|
@Override
|
@@ -101,34 +99,15 @@ public class GcsOutputPlugin implements FileOutputPlugin {
|
|
101
99
|
return new TransactionalGcsFileOutput(task, client, taskIndex);
|
102
100
|
}
|
103
101
|
|
104
|
-
private
|
102
|
+
private Storage createClient(final PluginTask task) {
|
103
|
+
Storage client = null;
|
105
104
|
try {
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
.setTransport(httpTransport)
|
111
|
-
.setJsonFactory(JSON_FACTORY)
|
112
|
-
.setServiceAccountId(task.getServiceAccountEmail())
|
113
|
-
.setServiceAccountScopes(ImmutableList.of(StorageScopes.DEVSTORAGE_READ_WRITE))
|
114
|
-
.setServiceAccountPrivateKeyFromP12File(new File(task.getP12KeyfilePath()))
|
115
|
-
.build();
|
116
|
-
return cred;
|
117
|
-
} catch (IOException ex) {
|
118
|
-
logger.error(String.format("Could not load client secrets file %s", task.getP12KeyfilePath()));
|
119
|
-
throw Throwables.propagate(ex);
|
120
|
-
} catch (GeneralSecurityException ex) {
|
121
|
-
logger.error("Google Authentication was failed");
|
122
|
-
throw Throwables.propagate(ex);
|
105
|
+
GcsAuthentication auth = new GcsAuthentication(task.getAuthMethod().getString(), task.getServiceAccountEmail(), task.getP12KeyfilePath(), task.getApplicationName());
|
106
|
+
client = auth.getGcsClient(task.getBucket());
|
107
|
+
} catch (GeneralSecurityException | IOException ex) {
|
108
|
+
throw new ConfigException(ex);
|
123
109
|
}
|
124
|
-
}
|
125
110
|
|
126
|
-
private Storage createClient(final PluginTask task) {
|
127
|
-
HttpTransport httpTransport = new ApacheHttpTransport.Builder().build();
|
128
|
-
Credential credential = createCredential(task, httpTransport);
|
129
|
-
Storage client = new Storage.Builder(httpTransport, JSON_FACTORY, credential)
|
130
|
-
.setApplicationName(task.getApplicationName())
|
131
|
-
.build();
|
132
111
|
return client;
|
133
112
|
}
|
134
113
|
|
@@ -194,8 +173,8 @@ public class GcsOutputPlugin implements FileOutputPlugin {
|
|
194
173
|
}
|
195
174
|
|
196
175
|
@Override
|
197
|
-
public
|
198
|
-
|
176
|
+
public TaskReport commit() {
|
177
|
+
TaskReport report = Exec.newTaskReport();
|
199
178
|
report.set("files", storageObjects);
|
200
179
|
return report;
|
201
180
|
}
|
@@ -250,4 +229,22 @@ public class GcsOutputPlugin implements FileOutputPlugin {
|
|
250
229
|
}
|
251
230
|
}
|
252
231
|
}
|
232
|
+
|
233
|
+
public enum AuthMethod
|
234
|
+
{
|
235
|
+
private_key("private_key"),
|
236
|
+
compute_engine("compute_engine");
|
237
|
+
|
238
|
+
private final String string;
|
239
|
+
|
240
|
+
AuthMethod(String string)
|
241
|
+
{
|
242
|
+
this.string = string;
|
243
|
+
}
|
244
|
+
|
245
|
+
public String getString()
|
246
|
+
{
|
247
|
+
return string;
|
248
|
+
}
|
249
|
+
}
|
253
250
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: embulk-output-gcs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kazuyuki Honda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,11 +59,12 @@ files:
|
|
59
59
|
- gradlew
|
60
60
|
- gradlew.bat
|
61
61
|
- lib/embulk/output/gcs.rb
|
62
|
+
- src/main/java/org/embulk/output/GcsAuthentication.java
|
62
63
|
- src/main/java/org/embulk/output/GcsOutputPlugin.java
|
63
64
|
- src/test/java/org/embulk/output/TestGcsOutputPlugin.java
|
64
65
|
- classpath/commons-codec-1.3.jar
|
65
66
|
- classpath/commons-logging-1.1.1.jar
|
66
|
-
- classpath/embulk-output-gcs-0.
|
67
|
+
- classpath/embulk-output-gcs-0.2.0.jar
|
67
68
|
- classpath/google-api-client-1.19.1.jar
|
68
69
|
- classpath/google-api-services-storage-v1-rev28-1.19.1.jar
|
69
70
|
- classpath/google-http-client-1.19.0.jar
|
Binary file
|