Skip to content

Commit 5690b46

Browse files
1 parent 482c797 commit 5690b46

File tree

5 files changed

+658
-6
lines changed

5 files changed

+658
-6
lines changed

google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClient.java

+184-6
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,26 @@
1515
*/
1616
package com.google.cloud.bigtable.admin.v2;
1717

18+
import com.google.api.core.ApiFunction;
19+
import com.google.api.core.ApiFuture;
20+
import com.google.api.core.ApiFutures;
21+
import com.google.bigtable.admin.v2.DeleteInstanceRequest;
22+
import com.google.bigtable.admin.v2.GetInstanceRequest;
23+
import com.google.bigtable.admin.v2.InstanceName;
24+
import com.google.bigtable.admin.v2.ListInstancesRequest;
25+
import com.google.bigtable.admin.v2.ListInstancesResponse;
26+
import com.google.bigtable.admin.v2.LocationName;
1827
import com.google.bigtable.admin.v2.ProjectName;
28+
import com.google.cloud.bigtable.admin.v2.models.CreateInstanceRequest;
29+
import com.google.cloud.bigtable.admin.v2.models.Instance;
30+
import com.google.cloud.bigtable.admin.v2.models.UpdateInstanceRequest;
1931
import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStub;
32+
import com.google.common.base.Verify;
33+
import com.google.common.collect.ImmutableList;
34+
import com.google.common.util.concurrent.MoreExecutors;
35+
import com.google.protobuf.Empty;
2036
import java.io.IOException;
37+
import java.util.List;
2138
import javax.annotation.Nonnull;
2239

2340
/**
@@ -27,14 +44,11 @@
2744
* <p>See the individual methods for example code.
2845
*
2946
* <pre>{@code
30-
* try(BigtableInstanceAdminClient client = BigtableInstanceAdminClient.create(ProjectName.of("my-project"))) {
47+
* try(BigtableInstanceAdminClient client = BigtableInstanceAdminClient.create(ProjectName.of("[PROJECT]"))) {
3148
* CreateInstanceRequest request = CreateInstanceRequest.of("my-instance")
32-
* .addFamily("cf1")
33-
* .addFamily("cf2", GCRULES.maxVersions(10))
34-
* .addSplit(ByteString.copyFromUtf8("b"))
35-
* .addSplit(ByteString.copyFromUtf8("q"));
49+
* .addCluster("my-cluster", "us-east1-c", 3, StorageType.SSD);
3650
*
37-
* client.createInstance(request);
51+
* Instance instance = client.createInstance(request);
3852
* }
3953
* }</pre>
4054
*
@@ -105,4 +119,168 @@ public ProjectName getProjectName() {
105119
public void close() {
106120
stub.close();
107121
}
122+
123+
/**
124+
* Creates a new instance and returns its representation.
125+
*
126+
* @see CreateInstanceRequest for details.
127+
*/
128+
public Instance createInstance(CreateInstanceRequest request) {
129+
return awaitFuture(createInstanceAsync(request));
130+
}
131+
132+
/**
133+
* Asynchronously creates a new instance and returns its representation wrapped in a future.
134+
*
135+
* @see CreateInstanceRequest for details.
136+
*/
137+
public ApiFuture<Instance> createInstanceAsync(CreateInstanceRequest request) {
138+
return ApiFutures.transform(
139+
stub.createInstanceOperationCallable().futureCall(request.toProto(projectName)),
140+
Instance.PROTO_TRANSFORMER,
141+
MoreExecutors.directExecutor());
142+
}
143+
144+
/**
145+
* Updates a new instance and returns its representation.
146+
*
147+
* @see UpdateInstanceRequest for details.
148+
*/
149+
public Instance updateInstance(UpdateInstanceRequest request) {
150+
return awaitFuture(updateInstanceAsync(request));
151+
}
152+
153+
/**
154+
* Asynchronously updates a new instance and returns its representation wrapped in a future.
155+
*
156+
* @see UpdateInstanceRequest for details.
157+
*/
158+
public ApiFuture<Instance> updateInstanceAsync(UpdateInstanceRequest request) {
159+
return ApiFutures.transform(
160+
stub.partialUpdateInstanceOperationCallable().futureCall(request.toProto(projectName)),
161+
Instance.PROTO_TRANSFORMER,
162+
MoreExecutors.directExecutor());
163+
}
164+
165+
/** Get the instance representation. */
166+
public Instance getInstance(String id) {
167+
return awaitFuture(getInstanceAsync(id));
168+
}
169+
170+
/** Asynchronously gets the instance representation wrapped in a future. */
171+
public ApiFuture<Instance> getInstanceAsync(String instanceId) {
172+
173+
InstanceName name = InstanceName.of(projectName.getProject(), instanceId);
174+
175+
GetInstanceRequest request = GetInstanceRequest.newBuilder()
176+
.setName(name.toString())
177+
.build();
178+
179+
return ApiFutures.transform(
180+
stub.getInstanceCallable().futureCall(request),
181+
Instance.PROTO_TRANSFORMER,
182+
MoreExecutors.directExecutor());
183+
}
184+
185+
/** Lists all of the instances in the current project. */
186+
public List<Instance> listInstances() {
187+
return awaitFuture(listInstancesAsync());
188+
}
189+
190+
/** Asynchronously lists all of the instances in the current project. */
191+
public ApiFuture<List<Instance>> listInstancesAsync() {
192+
ListInstancesRequest request = ListInstancesRequest.newBuilder()
193+
.setParent(projectName.toString())
194+
.build();
195+
196+
ApiFuture<ListInstancesResponse> responseFuture = stub.listInstancesCallable()
197+
.futureCall(request);
198+
199+
return ApiFutures.transform(responseFuture, new ApiFunction<ListInstancesResponse, List<Instance>>() {
200+
@Override
201+
public List<Instance> apply(ListInstancesResponse proto) {
202+
// NOTE: pagination is intentionally ignored. The server does not implement it.
203+
Verify.verify(proto.getNextPageToken().isEmpty(),
204+
"Server returned an unexpected paginated response");
205+
206+
ImmutableList.Builder<Instance> instances = ImmutableList.builder();
207+
208+
for (com.google.bigtable.admin.v2.Instance protoInstance : proto.getInstancesList()) {
209+
instances.add(Instance.PROTO_TRANSFORMER.apply(protoInstance));
210+
}
211+
212+
ImmutableList.Builder<String> failedZones = ImmutableList.builder();
213+
for (String locationStr : proto.getFailedLocationsList()) {
214+
failedZones.add(LocationName.parse(locationStr).getLocation());
215+
}
216+
217+
218+
if (!failedZones.build().isEmpty()) {
219+
throw new PartialListInstancesException(failedZones.build(), instances.build());
220+
}
221+
222+
return instances.build();
223+
}
224+
}, MoreExecutors.directExecutor());
225+
}
226+
227+
/** Deletes the specified instance. */
228+
public void deleteInstance(String instanceId) {
229+
awaitFuture(deleteInstanceAsync(instanceId));
230+
}
231+
232+
/** Asynchronously deletes the specified instance. */
233+
private ApiFuture<Void> deleteInstanceAsync(String instanceId) {
234+
InstanceName instanceName = InstanceName.of(projectName.getProject(), instanceId);
235+
236+
DeleteInstanceRequest request = DeleteInstanceRequest.newBuilder()
237+
.setName(instanceName.toString())
238+
.build();
239+
240+
return ApiFutures.transform(stub.deleteInstanceCallable().futureCall(request),
241+
new ApiFunction<Empty, Void>() {
242+
@Override
243+
public Void apply(Empty input) {
244+
return null;
245+
}
246+
},
247+
MoreExecutors.directExecutor()
248+
);
249+
}
250+
251+
252+
private <T> T awaitFuture(ApiFuture<T> future) {
253+
try {
254+
return future.get();
255+
} catch(Throwable t) {
256+
// TODO(igorbernstein2): figure out a better wrapper exception.
257+
throw new RuntimeException(t);
258+
}
259+
}
260+
261+
/**
262+
* Exception thrown when some zones are unavailable and listInstances is unable to return a full
263+
* instance list. This exception can be inspected to get a partial list.
264+
*/
265+
public static class PartialListInstancesException extends RuntimeException {
266+
private final List<String> failedZones;
267+
private final List<Instance> instances;
268+
269+
PartialListInstancesException(List<String> failedZones, List<Instance> instances) {
270+
super("Failed to list all instances, some zones where unavailable");
271+
272+
this.failedZones = failedZones;
273+
this.instances = instances;
274+
}
275+
276+
/** A list of zones, whose unavailability caused this error. */
277+
public List<String> getFailedZones() {
278+
return failedZones;
279+
}
280+
281+
/** A partial list of instances that were found in the available zones. */
282+
public List<Instance> getInstances() {
283+
return instances;
284+
}
285+
}
108286
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright 2018 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.google.cloud.bigtable.admin.v2.models;
17+
18+
import com.google.api.core.InternalApi;
19+
import com.google.bigtable.admin.v2.InstanceName;
20+
import com.google.bigtable.admin.v2.LocationName;
21+
import com.google.bigtable.admin.v2.ProjectName;
22+
import com.google.bigtable.admin.v2.StorageType;
23+
24+
/**
25+
* Parameters for creating a new Bigtable cluster.
26+
*
27+
* <p>A cluster represents the actual Cloud Bigtable service. Each cluster belongs to a single Cloud
28+
* Bigtable instance. When your application sends requests to a Cloud Bigtable instance, those
29+
* requests are actually handled by one of the clusters in the instance.
30+
*
31+
* <p>Each cluster is located in a single zone. An instance's clusters must be in unique zones that
32+
* are within the same region. For example, if the first cluster is in us-east1-b, then us-east1-c
33+
* is a valid zone for the second cluster. For a list of zones and regions where Cloud Bigtable is
34+
* available, see <a href="https://cloud.google.com/bigtable/docs/locations">Cloud Bigtable Locations</a>.
35+
*
36+
*
37+
* Examples:
38+
*
39+
* <pre>{@code
40+
* // Small production instance:
41+
* CreateClusterRequest clusterRequest = CreateClusterRequest.of("my-existing-instance", "my-cluster")
42+
* .setZone("us-east1-c")
43+
* .setServeNodes(3)
44+
* .setStorageType(StorageType.SSD);
45+
* }</pre>
46+
*
47+
* @see <a href="https://cloud.google.com/bigtable/docs/instances-clusters-nodes#clusters">For more details</a>
48+
*/
49+
public final class CreateClusterRequest {
50+
private final com.google.bigtable.admin.v2.CreateClusterRequest.Builder proto = com.google.bigtable.admin.v2.CreateClusterRequest
51+
.newBuilder();
52+
private final String instanceId;
53+
private String zone;
54+
55+
56+
/**
57+
* Builds a new request to create a new cluster to the specified instance with the specified
58+
* cluster id. */
59+
public static CreateClusterRequest of(String instanceId, String clusterId) {
60+
return new CreateClusterRequest(instanceId, clusterId);
61+
}
62+
63+
private CreateClusterRequest(String instanceId, String clusterId) {
64+
this.instanceId = instanceId;
65+
proto.setClusterId(clusterId);
66+
proto.getClusterBuilder().setDefaultStorageType(StorageType.SSD);
67+
}
68+
69+
/**
70+
* Sets the zone where the new cluster will be located. Must be different from the existing
71+
* cluster.
72+
*/
73+
public CreateClusterRequest setZone(String zone) {
74+
this.zone = zone;
75+
return this;
76+
}
77+
78+
/** Sets the type of storage used by this cluster to serve its parent instance's tables. */
79+
public CreateClusterRequest setServeNodes(int numNodes) {
80+
proto.getClusterBuilder().setServeNodes(numNodes);
81+
return this;
82+
}
83+
84+
/**
85+
* Sets the type of storage used by this cluster to serve its parent instance's tables.
86+
* Defaults to {@code SSD}.
87+
*/
88+
// TODO(igorbernstein2): try to avoid leaking protobuf generated enums
89+
public CreateClusterRequest setStorageType(StorageType storageType) {
90+
proto.getClusterBuilder().setDefaultStorageType(storageType);
91+
return this;
92+
}
93+
94+
/**
95+
* Creates the request protobuf. This method is considered an internal implementation detail and
96+
* not meant to be used by applications.
97+
*/
98+
@InternalApi
99+
public com.google.bigtable.admin.v2.CreateClusterRequest toProto(ProjectName projectName) {
100+
proto.setParent(InstanceName.of(projectName.getProject(), instanceId).toString());
101+
proto.getClusterBuilder().setLocation(LocationName.of(projectName.getProject(), zone).toString());
102+
103+
return proto.build();
104+
}
105+
106+
/**
107+
* Gets the clusterId. This method is meant to be used by {@link CreateClusterRequest} and is
108+
* considered an internal implementation detail and not meant to be used by applications.
109+
*/
110+
@InternalApi
111+
String getClusterId() {
112+
return proto.getClusterId();
113+
}
114+
115+
/**
116+
* Creates the request protobuf. This method is considered an internal implementation detail and
117+
* not meant to be used by applications.
118+
*/
119+
@InternalApi
120+
com.google.bigtable.admin.v2.Cluster toEmbeddedProto(ProjectName projectName) {
121+
proto.getClusterBuilder().setLocation(LocationName.of(projectName.getProject(), zone).toString());
122+
123+
return proto.getClusterBuilder().build();
124+
}
125+
}

0 commit comments

Comments
 (0)