18
18
import com .google .api .core .ApiFunction ;
19
19
import com .google .api .core .ApiFuture ;
20
20
import com .google .api .core .ApiFutures ;
21
+ import com .google .bigtable .admin .v2 .ClusterName ;
22
+ import com .google .bigtable .admin .v2 .DeleteClusterRequest ;
21
23
import com .google .bigtable .admin .v2 .DeleteInstanceRequest ;
24
+ import com .google .bigtable .admin .v2 .GetClusterRequest ;
22
25
import com .google .bigtable .admin .v2 .GetInstanceRequest ;
23
26
import com .google .bigtable .admin .v2 .InstanceName ;
27
+ import com .google .bigtable .admin .v2 .ListClustersRequest ;
28
+ import com .google .bigtable .admin .v2 .ListClustersResponse ;
24
29
import com .google .bigtable .admin .v2 .ListInstancesRequest ;
25
30
import com .google .bigtable .admin .v2 .ListInstancesResponse ;
26
31
import com .google .bigtable .admin .v2 .LocationName ;
27
32
import com .google .bigtable .admin .v2 .ProjectName ;
33
+ import com .google .cloud .bigtable .admin .v2 .models .Cluster ;
34
+ import com .google .cloud .bigtable .admin .v2 .models .CreateClusterRequest ;
28
35
import com .google .cloud .bigtable .admin .v2 .models .CreateInstanceRequest ;
29
36
import com .google .cloud .bigtable .admin .v2 .models .Instance ;
37
+ import com .google .cloud .bigtable .admin .v2 .models .PartialListClustersException ;
30
38
import com .google .cloud .bigtable .admin .v2 .models .PartialListInstancesException ;
31
39
import com .google .cloud .bigtable .admin .v2 .models .UpdateInstanceRequest ;
32
40
import com .google .cloud .bigtable .admin .v2 .stub .BigtableInstanceAdminStub ;
@@ -397,6 +405,282 @@ public Void apply(Empty input) {
397
405
);
398
406
}
399
407
408
+ /**
409
+ * Creates a new cluster in the specified instance.
410
+ *
411
+ * <p>Sample code:
412
+ *
413
+ * <pre>{@code
414
+ * Cluster cluster = client.createCluster(
415
+ * CreateClusterRequest.of("my-instance", "my-new-cluster")
416
+ * .setZone("us-east1-c")
417
+ * .setServeNodes(3)
418
+ * .setStorageType(StorageType.SSD)
419
+ * );
420
+ * }</pre>
421
+ */
422
+ @ SuppressWarnings ("WeakerAccess" )
423
+ public Cluster createCluster (CreateClusterRequest request ) {
424
+ return awaitFuture (createClusterAsync (request ));
425
+ }
426
+
427
+ /**
428
+ * Asynchronously creates a new cluster in the specified instance.
429
+ *
430
+ * <p>Sample code:
431
+ *
432
+ * <pre>{@code
433
+ * ApiFuture<Cluster> clusterFuture = client.createClusterAsync(
434
+ * CreateClusterRequest.of("my-instance", "my-new-cluster")
435
+ * .setZone("us-east1-c")
436
+ * .setServeNodes(3)
437
+ * .setStorageType(StorageType.SSD)
438
+ * );
439
+ *
440
+ * Cluster cluster = clusterFuture.get();
441
+ * }</pre>
442
+ */
443
+ @ SuppressWarnings ("WeakerAccess" )
444
+ public ApiFuture <Cluster > createClusterAsync (CreateClusterRequest request ) {
445
+ return ApiFutures .transform (
446
+ stub .createClusterOperationCallable ().futureCall (request .toProto (projectName )),
447
+ new ApiFunction <com .google .bigtable .admin .v2 .Cluster , Cluster >() {
448
+ @ Override
449
+ public Cluster apply (com .google .bigtable .admin .v2 .Cluster proto ) {
450
+ return Cluster .fromProto (proto );
451
+ }
452
+ },
453
+ MoreExecutors .directExecutor ()
454
+ );
455
+ }
456
+
457
+ /**
458
+ * Get the cluster representation by ID.
459
+ *
460
+ * <p>Sample code:
461
+ *
462
+ * <pre>{@code
463
+ * Cluster cluster = client.getCluster("my-instance", "my-cluster");
464
+ * }</pre>
465
+ */
466
+ @ SuppressWarnings ("WeakerAccess" )
467
+ public Cluster getCluster (String instanceId , String clusterId ) {
468
+ return awaitFuture (getClusterAsync (instanceId , clusterId ));
469
+ }
470
+
471
+ /**
472
+ * Asynchronously gets the cluster representation by ID.
473
+ *
474
+ * <p>Sample code:
475
+ *
476
+ * <pre>{@code
477
+ * ApiFuture<Cluster> clusterFuture = client.getClusterAsync("my-instance", "my-cluster");
478
+ * Cluster cluster = clusterFuture.get();
479
+ * }</pre>
480
+ */
481
+ @ SuppressWarnings ("WeakerAccess" )
482
+ public ApiFuture <Cluster > getClusterAsync (String instanceId , String clusterId ) {
483
+ ClusterName name = ClusterName .of (projectName .getProject (), instanceId , clusterId );
484
+
485
+ GetClusterRequest request = GetClusterRequest .newBuilder ()
486
+ .setName (name .toString ())
487
+ .build ();
488
+
489
+ return ApiFutures .transform (
490
+ stub .getClusterCallable ().futureCall (request ),
491
+ new ApiFunction <com .google .bigtable .admin .v2 .Cluster , Cluster >() {
492
+ @ Override
493
+ public Cluster apply (com .google .bigtable .admin .v2 .Cluster proto ) {
494
+ return Cluster .fromProto (proto );
495
+ }
496
+ },
497
+ MoreExecutors .directExecutor ()
498
+ );
499
+ }
500
+
501
+ /**
502
+ * Lists all clusters in the specified instance.
503
+ *
504
+ * <p>This method will throw a {@link PartialListClustersException} when any zone is
505
+ * unavailable. If partial listing are ok, the exception can be caught and inspected.
506
+ *
507
+ * <p>Sample code:
508
+ *
509
+ * <pre>{@code
510
+ * try {
511
+ * List<Cluster> clusters = cluster.listClusters("my-instance");
512
+ * } catch (PartialListClustersException e) {
513
+ * System.out.println("The following zones are unavailable: " + e.getUnavailableZones());
514
+ * System.out.println("But the following clusters are reachable: " + e.getClusters())
515
+ * }
516
+ * }</pre>
517
+ */
518
+ @ SuppressWarnings ("WeakerAccess" )
519
+ public List <Cluster > listClusters (String instanceId ) {
520
+ return awaitFuture (listClustersAsync (instanceId ));
521
+ }
522
+
523
+ /**
524
+ * Asynchronously lists all clusters in the specified instance.
525
+ *
526
+ * <p>This method will throw a {@link PartialListClustersException} when any zone is
527
+ * unavailable. If partial listing are ok, the exception can be caught and inspected.
528
+ *
529
+ * <p>Sample code:
530
+ *
531
+ * <pre>{@code
532
+ * ApiFuture<Cluster> clustersFuture = client.listClustersAsync("my-instance");
533
+ *
534
+ * ApiFutures.addCallback(clustersFuture, new ApiFutureCallback<List<Cluster>>() {
535
+ * public void onFailure(Throwable t) {
536
+ * if (t instanceof PartialListClustersException) {
537
+ * PartialListClustersException partialError = (PartialListClustersException)t;
538
+ * System.out.println("The following zones are unavailable: " + partialError.getUnavailableZones());
539
+ * System.out.println("But the following clusters are reachable: " + partialError.getClusters());
540
+ * } else {
541
+ * t.printStackTrace();
542
+ * }
543
+ * }
544
+ *
545
+ * public void onSuccess(List<Cluster> result) {
546
+ * System.out.println("Found a complete set of instances: " + result);
547
+ * }
548
+ * }, MoreExecutors.directExecutor());
549
+ * }</pre>
550
+ */
551
+ @ SuppressWarnings ("WeakerAccess" )
552
+ public ApiFuture <List <Cluster >> listClustersAsync (String instanceId ) {
553
+ InstanceName name = InstanceName .of (projectName .getProject (), instanceId );
554
+ ListClustersRequest request = ListClustersRequest .newBuilder ()
555
+ .setParent (name .toString ())
556
+ .build ();
557
+
558
+ return ApiFutures .transform (
559
+ stub .listClustersCallable ().futureCall (request ),
560
+ new ApiFunction <ListClustersResponse , List <Cluster >>() {
561
+ @ Override
562
+ public List <Cluster > apply (ListClustersResponse proto ) {
563
+ // NOTE: serverside pagination is not and will not be implemented, so remaining pages
564
+ // are not fetched. However, if that assumption turns out to be wrong, fail fast to
565
+ // avoid returning partial data.
566
+ Verify .verify (proto .getNextPageToken ().isEmpty (),
567
+ "Server returned an unexpected paginated response" );
568
+
569
+ ImmutableList .Builder <Cluster > clusters = ImmutableList .builder ();
570
+ for (com .google .bigtable .admin .v2 .Cluster cluster : proto .getClustersList ()) {
571
+ clusters .add (Cluster .fromProto (cluster ));
572
+ }
573
+
574
+ ImmutableList .Builder <String > failedZones = ImmutableList .builder ();
575
+ for (String locationStr : proto .getFailedLocationsList ()) {
576
+ LocationName fullLocation = Objects .requireNonNull (LocationName .parse (locationStr ));
577
+ failedZones .add (fullLocation .getLocation ());
578
+ }
579
+
580
+ if (!failedZones .build ().isEmpty ()) {
581
+ throw new PartialListClustersException (failedZones .build (), clusters .build ());
582
+ }
583
+
584
+ return clusters .build ();
585
+ }
586
+ },
587
+ MoreExecutors .directExecutor ()
588
+ );
589
+ }
590
+
591
+ /**
592
+ * Resizes the cluster's node count. Please note that only clusters that belong to a PRODUCTION
593
+ * instance can be resized.
594
+ *
595
+ * <p>Sample code:
596
+ *
597
+ * <pre>{@code
598
+ * Cluster cluster = cluster.resizeCluster("my-instance", "my-cluster", 30);
599
+ * }</pre>
600
+ */
601
+ @ SuppressWarnings ("WeakerAccess" )
602
+ public Cluster resizeCluster (String instanceId , String clusterId , int numServeNodes ) {
603
+ return awaitFuture (resizeClusterAsync (instanceId , clusterId , numServeNodes ));
604
+ }
605
+
606
+ /**
607
+ * Asynchronously resizes the cluster's node count. Please note that only clusters that belong to
608
+ * a PRODUCTION instance can be resized.
609
+ *
610
+ * <pre>{@code
611
+ * ApiFuture<Cluster> clusterFuture = cluster.resizeCluster("my-instance", "my-cluster", 30);
612
+ * Cluster cluster = clusterFuture.get();
613
+ * }</pre>
614
+ */
615
+ @ SuppressWarnings ("WeakerAccess" )
616
+ public ApiFuture <Cluster > resizeClusterAsync (String instanceId , String clusterId ,
617
+ int numServeNodes ) {
618
+
619
+ ClusterName name = ClusterName .of (projectName .getProject (), instanceId , clusterId );
620
+
621
+ com .google .bigtable .admin .v2 .Cluster request = com .google .bigtable .admin .v2 .Cluster .newBuilder ()
622
+ .setName (name .toString ())
623
+ .setServeNodes (numServeNodes )
624
+ .build ();
625
+
626
+ return ApiFutures .transform (
627
+ stub .updateClusterOperationCallable ().futureCall (request ),
628
+ new ApiFunction <com .google .bigtable .admin .v2 .Cluster , Cluster >() {
629
+ @ Override
630
+ public Cluster apply (com .google .bigtable .admin .v2 .Cluster proto ) {
631
+ return Cluster .fromProto (proto );
632
+ }
633
+ },
634
+ MoreExecutors .directExecutor ()
635
+ );
636
+ }
637
+
638
+ /**
639
+ * Deletes the specified cluster. Please note that an instance must have at least 1 cluster. To
640
+ * remove the last cluster, please use {@link BigtableInstanceAdminClient#deleteInstance(String)}.
641
+ *
642
+ * <p>Sample code:
643
+ *
644
+ * <pre>{@code
645
+ * client.deleteCluster("my-instance", "my-cluster");
646
+ * }</pre>
647
+ */
648
+ @ SuppressWarnings ("WeakerAccess" )
649
+ public void deleteCluster (String instanceId , String clusterId ) {
650
+ awaitFuture (deleteClusterAsync (instanceId , clusterId ));
651
+ }
652
+
653
+ /**
654
+ * Asynchronously deletes the specified cluster. Please note that an instance must have at least 1
655
+ * cluster. To remove the last cluster, please use {@link BigtableInstanceAdminClient#deleteInstanceAsync(String)}.
656
+ *
657
+ * <p>Sample code:
658
+ *
659
+ * <pre>{@code
660
+ * ApiFuture<Void> future = client.deleteClusterAsync("my-instance", "my-cluster");
661
+ * future.get();
662
+ * }</pre>
663
+ */
664
+ @ SuppressWarnings ("WeakerAccess" )
665
+ public ApiFuture <Void > deleteClusterAsync (String instanceId , String clusterId ) {
666
+ ClusterName name = ClusterName .of (projectName .getProject (), instanceId , clusterId );
667
+
668
+ DeleteClusterRequest request = DeleteClusterRequest .newBuilder ()
669
+ .setName (name .toString ())
670
+ .build ();
671
+
672
+ return ApiFutures .transform (
673
+ stub .deleteClusterCallable ().futureCall (request ),
674
+ new ApiFunction <Empty , Void >() {
675
+ @ Override
676
+ public Void apply (Empty input ) {
677
+ return null ;
678
+ }
679
+ },
680
+ MoreExecutors .directExecutor ()
681
+ );
682
+ }
683
+
400
684
/**
401
685
* Awaits the result of a future, taking care to propagate errors while maintaining the call site
402
686
* in a suppressed exception. This allows semantic errors to be caught across threads, while
@@ -406,7 +690,6 @@ public Void apply(Empty input) {
406
690
// TODO(igorbernstein2): try to move this into gax
407
691
private <T > T awaitFuture (ApiFuture <T > future ) {
408
692
RuntimeException error ;
409
-
410
693
try {
411
694
return Futures .getUnchecked (future );
412
695
} catch (UncheckedExecutionException e ) {
@@ -418,10 +701,8 @@ private <T> T awaitFuture(ApiFuture<T> future) {
418
701
} catch (RuntimeException e ) {
419
702
error = e ;
420
703
}
421
-
422
704
// Add the caller's stack as a suppressed exception
423
705
error .addSuppressed (new RuntimeException ("Encountered error while awaiting future" ));
424
-
425
706
throw error ;
426
707
}
427
708
}
0 commit comments