ignite-734: google cloud storage ipfinder is fully implemented
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/b98da84a Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/b98da84a Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/b98da84a Branch: refs/heads/ignite-789 Commit: b98da84a598e50d18134060cd4ff885563a62941 Parents: 546ec8e Author: Denis Magda <dma...@gridgain.com> Authored: Wed Apr 22 17:11:07 2015 +0300 Committer: Denis Magda <dma...@gridgain.com> Committed: Wed Apr 22 17:11:07 2015 +0300 ---------------------------------------------------------------------- .../google/TcpDiscoveryGoogleCloudIpFinder.java | 185 ++++++++++++------- 1 file changed, 123 insertions(+), 62 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/b98da84a/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/google/TcpDiscoveryGoogleCloudIpFinder.java ---------------------------------------------------------------------- diff --git a/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/google/TcpDiscoveryGoogleCloudIpFinder.java b/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/google/TcpDiscoveryGoogleCloudIpFinder.java index 3bfd8f3..4f7529f 100644 --- a/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/google/TcpDiscoveryGoogleCloudIpFinder.java +++ b/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/google/TcpDiscoveryGoogleCloudIpFinder.java @@ -18,15 +18,18 @@ package org.apache.ignite.spi.discovery.tcp.ipfinder.google; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.googleapis.json.GoogleJsonResponseException; import com.google.api.client.http.InputStreamContent; import com.google.api.client.http.javanet.NetHttpTransport; import com.google.api.services.storage.Storage; import com.google.api.services.storage.StorageScopes; import com.google.api.services.storage.model.*; import com.google.common.collect.ImmutableMap; +import org.apache.ignite.IgniteLogger; import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.resources.LoggerResource; import org.apache.ignite.spi.*; import org.apache.ignite.spi.discovery.tcp.ipfinder.*; @@ -42,17 +45,42 @@ import java.util.concurrent.atomic.AtomicBoolean; /** * Google Cloud Storage based IP finder. - * - * TODO: complete + * <p> + * For information about Cloud Storage visit <a href="https://cloud.google.com/storage/">cloud.google.com</a>. + * <h1 class="header">Configuration</h1> + * <h2 class="header">Mandatory</h2> + * <ul> + * <li>Service Account Id (see {@link #setServiceAccountId(String)})</li> + * <li>Service Account P12 key file path (see {@link #setServiceAccountP12FilePath(String)})</li> + * <li>Google Platform project name (see {@link #setProjectName(String)})</li> + * <li>Google Storage bucket name (see {@link #setBucketName(String)})</li> + * </ul> + * <h2 class="header">Optional</h2> + * <ul> + * <li>Shared flag (see {@link #setShared(boolean)})</li> + * </ul> + * <p> + * The finder will create a bucket with the provided name. The bucket will contain entries named + * like the following: {@code 192.168.1.136#1001}. + * <p> + * Note that storing data in Google Cloud Storage service will result in charges to your Google Cloud Platform account. + * Choose another implementation of {@link org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder} for local + * or home network tests. + * <p> + * Note that this finder is shared by default (see {@link org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder#isShared()}. */ public class TcpDiscoveryGoogleCloudIpFinder extends TcpDiscoveryIpFinderAdapter { /* Default object's content. */ - private final static ByteArrayInputStream OBJECT_CONTENT = new ByteArrayInputStream(new byte[1]); + private final static ByteArrayInputStream OBJECT_CONTENT = new ByteArrayInputStream(new byte[0]); + + /** Grid logger. */ + @LoggerResource + private IgniteLogger log; /* Google Cloud Platform's project name.*/ private String projectName; - /* Google Cloud Platform's bucket name. */ + /* Google Storage bucket name. */ private String bucketName; /* Service account p12 private key file name. */ @@ -146,7 +174,8 @@ public class TcpDiscoveryGoogleCloudIpFinder extends TcpDiscoveryIpFinderAdapter Storage.Objects.Delete deleteObject = storage.objects().delete(bucketName, key); deleteObject.execute(); - } catch (Exception e) { + } + catch (Exception e) { throw new IgniteSpiException("Failed to delete entry [bucketName=" + bucketName + ", entry=" + key + ']', e); } @@ -155,7 +184,8 @@ public class TcpDiscoveryGoogleCloudIpFinder extends TcpDiscoveryIpFinderAdapter /** * Sets Google Cloud Platforms project name. - * The project name is the one which your Google VM instances, Cloud Storage, etc. belong to. + * Usually this is an auto generated project number (ex. 208709979073) that can be found in "Overview" section + * of Google Developer Console. * <p> * For details refer to Google Cloud Platform API reference. * @@ -167,7 +197,10 @@ public class TcpDiscoveryGoogleCloudIpFinder extends TcpDiscoveryIpFinderAdapter } /** - * Sets Google Cloud Platforms bucket name. + * Sets Google Cloud Storage bucket name. + * If the bucket doesn't exist Ignite will automatically create it. However the name must be unique across whole + * Google Cloud Storage and Service Account Id (see {@link #setServiceAccountId(String)}) must be authorized to + * perform this operation. * * @param bucketName Bucket name. */ @@ -176,18 +209,37 @@ public class TcpDiscoveryGoogleCloudIpFinder extends TcpDiscoveryIpFinderAdapter this.bucketName = bucketName; } + + /** + * Sets a full path to the private key in PKCS12 format of the Service Account. + * <p> + * For more information refer to + * <a href="https://cloud.google.com/storage/docs/authentication#service_accounts">Service Account Authentication</a>. + * + * @param p12FileName Private key file full path. + */ @IgniteSpiConfiguration(optional = false) public void setServiceAccountP12FilePath(String p12FileName) { this.serviceAccountP12FilePath = p12FileName; } + /** + * Sets the service account ID (typically an e-mail address). + * <p> + * For more information refer to + * <a href="https://cloud.google.com/storage/docs/authentication#service_accounts">Service Account Authentication</a>. + * + * @param id + */ @IgniteSpiConfiguration(optional = false) public void setServiceAccountId(String id) { this.serviceAccountId = id; } /** + * Google Cloud Storage initialization. * + * @throws IgniteSpiException In case of error. */ private void init() throws IgniteSpiException { if (initGuard.compareAndSet(false, true)) { @@ -196,7 +248,8 @@ public class TcpDiscoveryGoogleCloudIpFinder extends TcpDiscoveryIpFinderAdapter try { httpTransport = GoogleNetHttpTransport.newTrustedTransport(); - } catch (GeneralSecurityException | IOException e) { + } + catch (GeneralSecurityException | IOException e) { throw new IgniteSpiException(e); } @@ -206,16 +259,55 @@ public class TcpDiscoveryGoogleCloudIpFinder extends TcpDiscoveryIpFinderAdapter credential = new GoogleCredential.Builder().setTransport(httpTransport) .setJsonFactory(JacksonFactory.getDefaultInstance()).setServiceAccountId(serviceAccountId) .setServiceAccountPrivateKeyFromP12File(new File(serviceAccountP12FilePath)) - .setServiceAccountScopes(Collections.singleton(StorageScopes.DEVSTORAGE_READ_WRITE)).build(); - } catch (Exception e) { + .setServiceAccountScopes(Collections.singleton(StorageScopes.DEVSTORAGE_FULL_CONTROL)).build(); + + } + catch (Exception e) { throw new IgniteSpiException("Failed to authenticate on Google Cloud Platform", e); } try { storage = new Storage.Builder(httpTransport, JacksonFactory.getDefaultInstance(), credential) .setApplicationName(projectName).build(); - } catch (Exception e) { - throw new IgniteSpiException("Failed to open a storage for given project name: " + projectName); + } + catch (Exception e) { + throw new IgniteSpiException("Failed to open a storage for given project name: " + projectName, e); + } + + boolean createBucket = false; + + try { + Storage.Buckets.Get getBucket = storage.buckets().get(bucketName); + getBucket.setProjection("full"); + + getBucket.execute(); + } + catch (GoogleJsonResponseException e) { + if (e.getStatusCode() == 404) { + U.warn(log, "Bucket doesn't exist, will create it [bucketName=" + bucketName + "]"); + createBucket = true; + } + else + throw new IgniteSpiException("Failed to open the bucket: " + bucketName, e); + } + catch (Exception e) { + throw new IgniteSpiException("Failed to open the bucket: " + bucketName, e); + } + + if (createBucket) { + Bucket newBucket = new Bucket(); + newBucket.setName(bucketName); + + try { + Storage.Buckets.Insert insertBucket = storage.buckets().insert(projectName, newBucket); + insertBucket.setProjection("full"); + insertBucket.setPredefinedDefaultObjectAcl("projectPrivate"); + + insertBucket.execute(); + } + catch (Exception e) { + throw new IgniteSpiException("Failed to create the bucket: " + bucketName, e); + } } } finally { @@ -225,7 +317,8 @@ public class TcpDiscoveryGoogleCloudIpFinder extends TcpDiscoveryIpFinderAdapter else { try { U.await(initLatch); - } catch (IgniteInterruptedCheckedException e) { + } + catch (IgniteInterruptedCheckedException e) { throw new IgniteSpiException("Thread has been interrupted.", e); } @@ -234,15 +327,28 @@ public class TcpDiscoveryGoogleCloudIpFinder extends TcpDiscoveryIpFinderAdapter } } + /** + * Constructs bucket's key from an address. + * + * @param addr Node address. + * @return Bucket key. + */ private String keyFromAddr(InetSocketAddress addr) { - return addr.getAddress().getHostAddress() + ":" + addr.getPort(); + return addr.getAddress().getHostAddress() + "#" + addr.getPort(); } - private InetSocketAddress addrFromString(String address) throws IgniteSpiException { - String[] res = address.split(":"); + /** + * Constructs a node address from bucket's key. + * + * @param key Bucket key. + * @return Node address. + * @throws IgniteSpiException In case of error. + */ + private InetSocketAddress addrFromString(String key) throws IgniteSpiException { + String[] res = key.split("#"); if (res.length != 2) - throw new IgniteSpiException("Invalid address string: " + address); + throw new IgniteSpiException("Invalid address string: " + key); int port; @@ -255,49 +361,4 @@ public class TcpDiscoveryGoogleCloudIpFinder extends TcpDiscoveryIpFinderAdapter return new InetSocketAddress(res[0], port); } - - - - public static void main(String args[]) { - TcpDiscoveryGoogleCloudIpFinder ipFinder = new TcpDiscoveryGoogleCloudIpFinder(); - - String bucketName = "grid-gain-test-bucket1"; - - ipFinder.setBucketName(bucketName); - ipFinder.setProjectName("gridgain"); - ipFinder.setServiceAccountId("208709979073-v0mn6ttpd3mqu2b5lbhh1mvdet7os...@developer.gserviceaccount.com"); - ipFinder.setServiceAccountP12FilePath("C:\\ignite\\GCE\\gridgain-0889e44b58b7.p12"); - - List<InetSocketAddress> addresses = new LinkedList<>(); - addresses.add(new InetSocketAddress("192.168.0.1", 23)); - addresses.add(new InetSocketAddress("192.168.0.1", 89)); - addresses.add(new InetSocketAddress("92.68.0.1", 1223)); - - System.out.println("PUT ADDR"); - ipFinder.registerAddresses(addresses); - - Collection<InetSocketAddress> result = ipFinder.getRegisteredAddresses(); - System.out.println("GET ADDR"); - - for (InetSocketAddress add: result) { - System.out.println(add.getAddress().getHostAddress() + ":" + add.getPort()); - } - - System.out.println("REMOVE"); - ipFinder.unregisterAddresses(addresses); - - - result = ipFinder.getRegisteredAddresses(); - System.out.println("GET ADDR 2"); - - for (InetSocketAddress add: result) { - System.out.println(add.getAddress().getHostAddress() + ":" + add.getPort()); - } - - List<InetSocketAddress> addresses2 = new LinkedList<>(); - addresses.add(new InetSocketAddress("192.1638.02.1", 23)); - ipFinder.unregisterAddresses(addresses2); - } - - }