{@code
* try(BigtableInstanceAdminClient client = BigtableInstanceAdminClient.create(ProjectName.of("my-project"))) {
* CreateInstanceRequest request = CreateInstanceRequest.of("my-instance")
- * .addFamily("cf1")
- * .addFamily("cf2", GCRULES.maxVersions(10))
- * .addSplit(ByteString.copyFromUtf8("b"))
- * .addSplit(ByteString.copyFromUtf8("q"));
+ * .addCluster("my-cluster", "us-east1-c", 3, StorageType.SSD);
*
- * client.createInstance(request);
+ * Instance instance = client.createInstance(request);
* }
* }
*
@@ -48,7 +66,7 @@
*
* {@code
* BigtableInstanceAdminSettings settings = BigtableInstanceAdminSettings.newBuilder()
- * .setProjectName(ProjectName.of("[PROJECT]"))
+ * .setProjectName(ProjectName.of("my-project"))
* .setCredentialsProvider(FixedCredentialsProvider.create(myCredentials))
* .build();
*
@@ -59,7 +77,7 @@
*
* {@code
* BigtableInstanceAdminSettings settings = BigtableInstanceAdminSettings.newBuilder()
- * .setProjectName(ProjectName.of("[PROJECT]"))
+ * .setProjectName(ProjectName.of("my-project"))
* .setEndpoint(myEndpoint)
* .build();
*
@@ -82,7 +100,7 @@ public static BigtableInstanceAdminClient create(@Nonnull BigtableInstanceAdminS
return create(settings.getProjectName(), settings.getStubSettings().createStub());
}
- /** Constructs an instance of BigtableInstanceAdminClient with the given Projectname and stub. */
+ /** Constructs an instance of BigtableInstanceAdminClient with the given ProjectName and stub. */
public static BigtableInstanceAdminClient create(@Nonnull ProjectName projectName,
@Nonnull BigtableInstanceAdminStub stub) {
return new BigtableInstanceAdminClient(projectName, stub);
@@ -96,6 +114,7 @@ private BigtableInstanceAdminClient(
}
/** Gets the ProjectName this client is associated with. */
+ @SuppressWarnings("WeakerAccess")
public ProjectName getProjectName() {
return projectName;
}
@@ -105,4 +124,304 @@ public ProjectName getProjectName() {
public void close() {
stub.close();
}
+
+ /**
+ * Creates a new instance and returns its representation.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * Instance instance = client.createInstance(
+ * CreateInstanceRequest.of("my-instance")
+ * .addCluster("my-cluster", "us-east1-c", 3, StorageType.SSD)
+ * );
+ * }
+ *
+ * @see CreateInstanceRequest for details.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public Instance createInstance(CreateInstanceRequest request) {
+ return awaitFuture(createInstanceAsync(request));
+ }
+
+ /**
+ * Asynchronously creates a new instance and returns its representation wrapped in a future.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * ApiFuture instanceFuture = client.createInstanceAsync(
+ * CreateInstanceRequest.of("my-instance")
+ * .addCluster("my-cluster", "us-east1-c", 3, StorageType.SSD)
+ * );
+ *
+ * Instance instance = instanceFuture.get();
+ * }
+ *
+ * @see CreateInstanceRequest for details.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public ApiFuture createInstanceAsync(CreateInstanceRequest request) {
+ return ApiFutures.transform(
+ stub.createInstanceOperationCallable().futureCall(request.toProto(projectName)),
+ new ApiFunction() {
+ @Override
+ public Instance apply(com.google.bigtable.admin.v2.Instance proto) {
+ return Instance.fromProto(proto);
+ }
+ },
+ MoreExecutors.directExecutor());
+ }
+
+ /**
+ * Updates a new instance and returns its representation.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * Instance instance = client.updateInstance(
+ * UpdateInstanceRequest.of("my-instance")
+ * .setProductionType()
+ * );
+ * }
+ *
+ * @see UpdateInstanceRequest for details.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public Instance updateInstance(UpdateInstanceRequest request) {
+ return awaitFuture(updateInstanceAsync(request));
+ }
+
+ /**
+ * Asynchronously updates a new instance and returns its representation wrapped in a future.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * ApiFuture instanceFuture = client.updateInstanceAsync(
+ * UpdateInstanceRequest.of("my-instance")
+ * .setProductionType()
+ * );
+ *
+ * Instance instance = instanceFuture.get();
+ * }
+ *
+ * @see UpdateInstanceRequest for details.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public ApiFuture updateInstanceAsync(UpdateInstanceRequest request) {
+ return ApiFutures.transform(
+ stub.partialUpdateInstanceOperationCallable().futureCall(request.toProto(projectName)),
+ new ApiFunction() {
+ @Override
+ public Instance apply(com.google.bigtable.admin.v2.Instance proto) {
+ return Instance.fromProto(proto);
+ }
+ },
+ MoreExecutors.directExecutor());
+ }
+
+ /**
+ * Get the instance representation by ID.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * Instance instance = client.getInstance("my-instance");
+ * }
+ */
+ @SuppressWarnings("WeakerAccess")
+ public Instance getInstance(String id) {
+ return awaitFuture(getInstanceAsync(id));
+ }
+
+ /**
+ * Asynchronously gets the instance representation by ID wrapped in a future.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * ApiFuture instanceFuture = client.getInstanceAsync("my-instance");
+ * Instance instance = instanceFuture.get();
+ * }
+ */
+ @SuppressWarnings("WeakerAccess")
+ public ApiFuture getInstanceAsync(String instanceId) {
+ InstanceName name = InstanceName.of(projectName.getProject(), instanceId);
+
+ GetInstanceRequest request = GetInstanceRequest.newBuilder()
+ .setName(name.toString())
+ .build();
+
+ return ApiFutures.transform(
+ stub.getInstanceCallable().futureCall(request),
+ new ApiFunction() {
+ @Override
+ public Instance apply(com.google.bigtable.admin.v2.Instance proto) {
+ return Instance.fromProto(proto);
+ }
+ },
+ MoreExecutors.directExecutor());
+ }
+
+ /**
+ * Lists all of the instances in the current project.
+ *
+ * This method will throw a {@link PartialListInstancesException} when any zone is
+ * unavailable. If partial listing are ok, the exception can be caught and inspected.
+ *
+ *
Sample code:
+ *
+ *
{@code
+ * try {
+ * List instances = client.listInstances();
+ * } catch (PartialListInstancesException e) {
+ * System.out.println("The following zones are unavailable: " + e.getUnavailableZones());
+ * System.out.println("But the following instances are reachable: " + e.getInstances());
+ * }
+ * }
+ */
+ @SuppressWarnings("WeakerAccess")
+ public List listInstances() {
+ return awaitFuture(listInstancesAsync());
+ }
+
+ /**
+ * Asynchronously lists all of the instances in the current project.
+ *
+ * This method will throw a {@link PartialListInstancesException} when any zone is
+ * unavailable.
+ * If partial listing are ok, the exception can be caught and inspected.
+ *
+ *
Sample code:
+ *
+ *
{@code
+ * ApiFuture instancesFuture = client.listInstancesAsync();
+ *
+ * ApiFutures.addCallback(instancesFuture, new ApiFutureCallback>() {
+ * public void onFailure(Throwable t) {
+ * if (t instanceof PartialListInstancesException) {
+ * PartialListInstancesException partialError = (PartialListInstancesException)t;
+ * System.out.println("The following zones are unavailable: " + partialError.getUnavailableZones());
+ * System.out.println("But the following instances are reachable: " + partialError.getInstances());
+ * } else {
+ * t.printStackTrace();
+ * }
+ * }
+ *
+ * public void onSuccess(List result) {
+ * System.out.println("Found a complete set of instances: " + result);
+ * }
+ * }, MoreExecutors.directExecutor());
+ * }
+ */
+ @SuppressWarnings("WeakerAccess")
+ public ApiFuture> listInstancesAsync() {
+ ListInstancesRequest request = ListInstancesRequest.newBuilder()
+ .setParent(projectName.toString())
+ .build();
+
+ ApiFuture responseFuture = stub.listInstancesCallable()
+ .futureCall(request);
+
+ return ApiFutures
+ .transform(responseFuture, new ApiFunction>() {
+ @Override
+ public List apply(ListInstancesResponse proto) {
+ // NOTE: pagination is intentionally ignored. The server does not implement it and never
+ // will.
+ Verify.verify(proto.getNextPageToken().isEmpty(),
+ "Server returned an unexpected paginated response");
+
+ ImmutableList.Builder instances = ImmutableList.builder();
+
+ for (com.google.bigtable.admin.v2.Instance protoInstance : proto.getInstancesList()) {
+ instances.add(Instance.fromProto(protoInstance));
+ }
+
+ ImmutableList.Builder failedZones = ImmutableList.builder();
+ for (String locationStr : proto.getFailedLocationsList()) {
+ LocationName fullLocation = Objects.requireNonNull(LocationName.parse(locationStr));
+ failedZones.add(fullLocation.getLocation());
+ }
+
+ if (!failedZones.build().isEmpty()) {
+ throw new PartialListInstancesException(failedZones.build(), instances.build());
+ }
+
+ return instances.build();
+ }
+ }, MoreExecutors.directExecutor());
+ }
+
+ /**
+ * Deletes the specified instance.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * client.deleteInstance("my-instance");
+ * }
+ */
+ @SuppressWarnings("WeakerAccess")
+ public void deleteInstance(String instanceId) {
+ awaitFuture(deleteInstanceAsync(instanceId));
+ }
+
+ /**
+ * Asynchronously deletes the specified instance.
+ *
+ * Sample code:
+ *
+ *
{@code
+ * ApiFuture deleteFuture = client.deleteInstance("my-instance");
+ * deleteFuture.get();
+ * }
+ */
+ @SuppressWarnings("WeakerAccess")
+ public ApiFuture deleteInstanceAsync(String instanceId) {
+ InstanceName instanceName = InstanceName.of(projectName.getProject(), instanceId);
+
+ DeleteInstanceRequest request = DeleteInstanceRequest.newBuilder()
+ .setName(instanceName.toString())
+ .build();
+
+ return ApiFutures.transform(stub.deleteInstanceCallable().futureCall(request),
+ new ApiFunction() {
+ @Override
+ public Void apply(Empty input) {
+ return null;
+ }
+ },
+ MoreExecutors.directExecutor()
+ );
+ }
+
+ /**
+ * Awaits the result of a future, taking care to propagate errors while maintaining the call site
+ * in a suppressed exception. This allows semantic errors to be caught across threads, while
+ * preserving the call site in the error. The caller's stacktrace will be made available as a
+ * suppressed exception.
+ */
+ // TODO(igorbernstein2): try to move this into gax
+ private T awaitFuture(ApiFuture future) {
+ RuntimeException error;
+
+ try {
+ return Futures.getUnchecked(future);
+ } catch (UncheckedExecutionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ error = (RuntimeException) e.getCause();
+ } else {
+ error = e;
+ }
+ } catch (RuntimeException e) {
+ error = e;
+ }
+
+ // Add the caller's stack as a suppressed exception
+ error.addSuppressed(new RuntimeException("Encountered error while awaiting future"));
+
+ throw error;
+ }
}
diff --git a/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/CreateClusterRequest.java b/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/CreateClusterRequest.java
new file mode 100644
index 000000000000..d653be2ac99b
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/CreateClusterRequest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigtable.admin.v2.models;
+
+import com.google.api.core.InternalApi;
+import com.google.bigtable.admin.v2.InstanceName;
+import com.google.bigtable.admin.v2.LocationName;
+import com.google.bigtable.admin.v2.ProjectName;
+import com.google.bigtable.admin.v2.StorageType;
+
+/**
+ * Parameters for creating a new Bigtable cluster.
+ *
+ * A cluster represents the actual Cloud Bigtable service. Each cluster belongs to a single Cloud
+ * Bigtable instance. When your application sends requests to a Cloud Bigtable instance, those
+ * requests are actually handled by one of the clusters in the instance.
+ *
+ *
Each cluster is located in a single zone. An instance's clusters must be in unique zones that
+ * are within the same region. For example, if the first cluster is in us-east1-b, then us-east1-c
+ * is a valid zone for the second cluster. For a list of zones and regions where Cloud Bigtable is
+ * available, see Cloud Bigtable Locations.
+ *
+ *
+ * Examples:
+ *
+ *
{@code
+ * // Small production instance:
+ * CreateClusterRequest clusterRequest = CreateClusterRequest.of("my-existing-instance", "my-cluster")
+ * .setZone("us-east1-c")
+ * .setServeNodes(3)
+ * .setStorageType(StorageType.SSD);
+ * }
+ *
+ * @see For more details
+ */
+public final class CreateClusterRequest {
+ private final com.google.bigtable.admin.v2.CreateClusterRequest.Builder proto = com.google.bigtable.admin.v2.CreateClusterRequest
+ .newBuilder();
+ // instanceId and zone are short ids, which will be expanded to full names when the project name
+ // is passed to toProto
+ private final String instanceId;
+ private String zone;
+
+
+ /**
+ * Builds a new request to create a new cluster to the specified instance with the specified
+ * cluster id. */
+ public static CreateClusterRequest of(String instanceId, String clusterId) {
+ return new CreateClusterRequest(instanceId, clusterId);
+ }
+
+ private CreateClusterRequest(String instanceId, String clusterId) {
+ this.instanceId = instanceId;
+ proto.setClusterId(clusterId);
+ proto.getClusterBuilder().setDefaultStorageType(StorageType.SSD);
+ }
+
+ /**
+ * Sets the zone where the new cluster will be located. Must be different from the existing
+ * cluster.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public CreateClusterRequest setZone(String zone) {
+ this.zone = zone;
+ return this;
+ }
+
+ /** Sets the number of nodes allocated to this cluster. More nodes enable higher throughput and
+ * more consistent performance. */
+ @SuppressWarnings("WeakerAccess")
+ public CreateClusterRequest setServeNodes(int numNodes) {
+ proto.getClusterBuilder().setServeNodes(numNodes);
+ return this;
+ }
+
+ /**
+ * Sets the type of storage used by this cluster to serve its parent instance's tables.
+ * Defaults to {@code SSD}.
+ */
+ // TODO(igorbernstein2): try to avoid leaking protobuf generated enums
+ @SuppressWarnings("WeakerAccess")
+ public CreateClusterRequest setStorageType(StorageType storageType) {
+ proto.getClusterBuilder().setDefaultStorageType(storageType);
+ return this;
+ }
+
+ /**
+ * Creates the request protobuf. This method is considered an internal implementation detail and
+ * not meant to be used by applications.
+ */
+ @InternalApi
+ public com.google.bigtable.admin.v2.CreateClusterRequest toProto(ProjectName projectName) {
+ proto.setParent(InstanceName.of(projectName.getProject(), instanceId).toString());
+ proto.getClusterBuilder().setLocation(LocationName.of(projectName.getProject(), zone).toString());
+
+ return proto.build();
+ }
+
+ /**
+ * Gets the clusterId. This method is meant to be used by {@link CreateClusterRequest} and is
+ * considered an internal implementation detail and not meant to be used by applications.
+ */
+ @InternalApi
+ String getClusterId() {
+ return proto.getClusterId();
+ }
+
+ /**
+ * Creates the request protobuf to be used in {@link CreateInstanceRequest}. This method is
+ * considered an internal implementation detail and not meant to be used by applications.
+ */
+ @InternalApi
+ com.google.bigtable.admin.v2.Cluster toEmbeddedProto(ProjectName projectName) {
+ proto.getClusterBuilder().setLocation(LocationName.of(projectName.getProject(), zone).toString());
+
+ return proto.getClusterBuilder().build();
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/CreateInstanceRequest.java b/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/CreateInstanceRequest.java
new file mode 100644
index 000000000000..3def1a20ca8e
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/CreateInstanceRequest.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigtable.admin.v2.models;
+
+import com.google.api.core.InternalApi;
+import com.google.bigtable.admin.v2.Instance.Type;
+import com.google.bigtable.admin.v2.ProjectName;
+import com.google.bigtable.admin.v2.StorageType;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import java.util.List;
+import javax.annotation.Nonnull;
+
+/**
+ * Parameters for creating a new Bigtable Instance.
+ *
+ * A Cloud Bigtable instance is mostly just a container for your clusters and nodes,
+ * which do all of the real work. Instances come in 2 flavors:
+ *
+ *
+ * - Production
+ *
- A standard instance with either 1 or 2 clusters, as well as 3 or more nodes in each cluster.
+ * You cannot downgrade a production instance to a development instance.
+ *
+ *
- Development
+ *
- A low-cost instance for development and testing, with performance limited to the equivalent
+ * of a 1-node cluster. Development instances only support a single 1 node cluster.
+ *
+ *
+ * When creating an Instance, you must create at least one cluster in it.
+ *
+ * Examples:
+ *
+ * {@code
+ * // Small production instance:
+ * CreateInstanceRequest smallProdInstanceRequest = CreateInstanceRequest.of("my-small-instance")
+ * .addCluster("cluster1", "us-east1-c", 3, StorageType.SSD);
+ *
+ * // Development instance:
+ * CreateInstanceRequest smallProdInstanceRequest = CreateInstanceRequest.of("my-dev-instance")
+ * .setType(Type.DEVELOPMENT)
+ * .addCluster("cluster1", "us-east1-c", 1, StorageType.SSD);
+ *
+ * }
+ *
+ * @see For more details
+ */
+public final class CreateInstanceRequest {
+ private final com.google.bigtable.admin.v2.CreateInstanceRequest.Builder builder =
+ com.google.bigtable.admin.v2.CreateInstanceRequest.newBuilder();
+
+ private final List clusterRequests = Lists.newArrayList();
+
+ /** Builds a new request to create a new instance with the specified id. */
+ public static CreateInstanceRequest of(@Nonnull String instanceId) {
+ return new CreateInstanceRequest(instanceId);
+ }
+
+ private CreateInstanceRequest(@Nonnull String instanceId) {
+ Preconditions.checkNotNull(instanceId, "InstanceId can't be null");
+
+ builder.setInstanceId(instanceId);
+ builder.getInstanceBuilder().setDisplayName(instanceId);
+ builder.getInstanceBuilder().setType(Type.PRODUCTION);
+ }
+
+ /**
+ * Sets the friendly display name of the instance. If left unspecified, it will default to the id
+ */
+ @SuppressWarnings("WeakerAccess")
+ public CreateInstanceRequest setDisplayName(@Nonnull String displayName) {
+ Preconditions.checkNotNull(displayName);
+ builder.getInstanceBuilder().setDisplayName(displayName);
+ return this;
+ }
+
+ /**
+ * Sets the type of instance.
+ *
+ * Can be either DEVELOPMENT or PRODUCTION. Defaults to PRODUCTION.
+ * Please see class javadoc for details.
+ */
+ // TODO(igorbernstein2): try to avoid leaking protobuf generated enums
+ @SuppressWarnings("WeakerAccess")
+ public CreateInstanceRequest setType(@Nonnull Type type) {
+ Preconditions.checkNotNull(type);
+ builder.getInstanceBuilder().setType(type);
+ return this;
+ }
+
+ /**
+ * Adds an arbitrary label to the instance.
+ *
+ *
Labels are key-value pairs that you can use to group related instances and store metadata
+ * about an instance.
+ *
+ * @see For more details
+ */
+ @SuppressWarnings("WeakerAccess")
+ public CreateInstanceRequest addLabel(@Nonnull String key, @Nonnull String value) {
+ Preconditions.checkNotNull(key, "Key can't be null");
+ Preconditions.checkNotNull(value, "Value can't be null");
+ builder.getInstanceBuilder().putLabels(key, value);
+ return this;
+ }
+
+ /**
+ * Adds a cluster to the instance request.
+ *
+ *
All new instances must have at least one cluster. DEVELOPMENT instances must have exactly
+ * one cluster.
+ *
+ * @param clusterId The name of the cluster.
+ * @param zone The zone where the cluster will be created.
+ * @param serveNodes The number of nodes that cluster will contain. DEVELOPMENT instance clusters must have exactly one node.
+ * @param storageType The type of storage used by this cluster to serve its parent instance's tables.
+ */
+ // TODO(igorbernstein2): try to avoid leaking protobuf generated enums
+ @SuppressWarnings("WeakerAccess")
+ public CreateInstanceRequest addCluster(@Nonnull String clusterId, @Nonnull String zone, int serveNodes, @Nonnull StorageType storageType) {
+ CreateClusterRequest clusterRequest = CreateClusterRequest
+ .of("ignored-instance-id", clusterId)
+ .setZone(zone)
+ .setServeNodes(serveNodes)
+ .setStorageType(storageType);
+ clusterRequests.add(clusterRequest);
+
+ return this;
+ }
+
+ /**
+ * Creates the request protobuf. This method is considered an internal implementation detail and
+ * not meant to be used by applications.
+ */
+ @InternalApi
+ public com.google.bigtable.admin.v2.CreateInstanceRequest toProto(ProjectName projectName) {
+ builder
+ .setParent(projectName.toString())
+ .clearClusters();
+
+ for (CreateClusterRequest clusterRequest : clusterRequests) {
+ builder.putClusters(clusterRequest.getClusterId(), clusterRequest.toEmbeddedProto(projectName));
+ }
+
+ return builder.build();
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/Instance.java b/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/Instance.java
new file mode 100644
index 000000000000..5d067aaaa24e
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/Instance.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigtable.admin.v2.models;
+
+import com.google.api.core.InternalApi;
+import com.google.bigtable.admin.v2.Instance.State;
+import com.google.bigtable.admin.v2.Instance.Type;
+import com.google.bigtable.admin.v2.InstanceName;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Verify;
+import java.util.Map;
+import javax.annotation.Nonnull;
+
+/**
+ * Represents an existing Cloud Bigtable instance.
+ *
+ *
A Cloud Bigtable instance is mostly just a container for your clusters and nodes, which do
+ * all of the real work.
+ */
+public final class Instance {
+ @Nonnull
+ private final com.google.bigtable.admin.v2.Instance proto;
+
+ /**
+ * Wraps the protobuf. This method is considered an internal implementation detail and not meant
+ * to be used by applications.
+ */
+ @InternalApi
+ public static Instance fromProto(@Nonnull com.google.bigtable.admin.v2.Instance proto) {
+ return new Instance(proto);
+ }
+
+ private Instance(@Nonnull com.google.bigtable.admin.v2.Instance proto) {
+ Preconditions.checkNotNull(proto);
+ Preconditions.checkArgument(!proto.getName().isEmpty(), "Name must be set");
+ this.proto = proto;
+ }
+
+ /** Gets the instance's id. */
+ @SuppressWarnings("WeakerAccess")
+ public String getId() {
+ // Constructor ensures that name is not null
+ InstanceName fullName = Verify.verifyNotNull(
+ InstanceName.parse(proto.getName()),
+ "Name can never be null");
+
+ //noinspection ConstantConditions
+ return fullName.getInstance();
+ }
+
+ /** Gets the instance's friendly name. */
+ @SuppressWarnings("WeakerAccess")
+ public String getDisplayName() {
+ return proto.getDisplayName();
+ }
+
+ /** Gets the instance's current type. Can be DEVELOPMENT or PRODUCTION. */
+ @SuppressWarnings("WeakerAccess")
+ public Type getType() {
+ return proto.getType();
+ }
+
+ /**
+ * Gets the current labels associated with the instance.
+ *
+ * @see For more
+ * details
+ */
+ @SuppressWarnings("WeakerAccess")
+ public Map getLabels() {
+ return proto.getLabelsMap();
+ }
+
+
+ /** The current state of the instance. */
+ // TODO(igorbernstein2): Try to avoid leaking protobuf enums
+ @SuppressWarnings("WeakerAccess")
+ public State getState() {
+ return proto.getState();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Instance instance = (Instance) o;
+ return Objects.equal(proto, instance.proto);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(proto);
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/PartialListInstancesException.java b/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/PartialListInstancesException.java
new file mode 100644
index 000000000000..81bbc796afb8
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/PartialListInstancesException.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigtable.admin.v2.models;
+
+import com.google.api.core.InternalApi;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import javax.annotation.Nonnull;
+
+/**
+ * Exception thrown when some zones are unavailable and listInstances is unable to return a full
+ * instance list. This exception can be inspected to get a partial list.
+ */
+public class PartialListInstancesException extends RuntimeException {
+ private final List unavailableZones;
+ private final List instances;
+
+ @InternalApi
+ public PartialListInstancesException(@Nonnull List unavailableZones, @Nonnull List instances) {
+ super("Failed to list all instances, some zones where unavailable");
+
+ this.unavailableZones = ImmutableList.copyOf(unavailableZones);
+ this.instances = ImmutableList.copyOf(instances);
+ }
+
+ /** A list of zones, whose unavailability caused this error. */
+ public List getUnavailableZones() {
+ return unavailableZones;
+ }
+
+ /** A partial list of instances that were found in the available zones. */
+ public List getInstances() {
+ return instances;
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/UpdateInstanceRequest.java b/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/UpdateInstanceRequest.java
new file mode 100644
index 000000000000..ebfda5eb576f
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/models/UpdateInstanceRequest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigtable.admin.v2.models;
+
+import com.google.api.core.InternalApi;
+import com.google.bigtable.admin.v2.Instance;
+import com.google.bigtable.admin.v2.Instance.Type;
+import com.google.bigtable.admin.v2.InstanceName;
+import com.google.bigtable.admin.v2.PartialUpdateInstanceRequest;
+import com.google.bigtable.admin.v2.ProjectName;
+import com.google.common.base.Preconditions;
+import com.google.protobuf.FieldMask;
+import com.google.protobuf.util.FieldMaskUtil;
+import java.util.Map;
+import javax.annotation.Nonnull;
+
+/**
+ * Parameters for updating an existing Bigtable instance.
+ *
+ * Existing instances maybe updated to change their superficial appearance (ie. display name)
+ * and can also be upgraded from a DEVELOPMENT instance to a PRODUCTION instance. Please note that
+ * upgrading to a PRODUCTION instance cannot be undone.
+ */
+public class UpdateInstanceRequest {
+ private final String instanceId;
+ private final PartialUpdateInstanceRequest.Builder builder = PartialUpdateInstanceRequest
+ .newBuilder();
+
+ /** Builds a new request to update an existing instance with the specified id. */
+ public static UpdateInstanceRequest of(@Nonnull String instanceId) {
+ return new UpdateInstanceRequest(instanceId);
+ }
+
+ private UpdateInstanceRequest(@Nonnull String instanceId) {
+ Preconditions.checkNotNull(instanceId, "instanceId can't be null");
+ this.instanceId = instanceId;
+ }
+
+ /** Changes the display name of the instance. */
+ @SuppressWarnings("WeakerAccess")
+ public UpdateInstanceRequest setDisplayName(@Nonnull String displayName) {
+ Preconditions.checkNotNull(displayName);
+ builder.getInstanceBuilder().setDisplayName(displayName);
+ updateFieldMask(Instance.DISPLAY_NAME_FIELD_NUMBER);
+
+ return this;
+ }
+
+ /**
+ * Upgrades the instance from a DEVELOPMENT instance to a PRODUCTION instance. This cannot be
+ * undone.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public UpdateInstanceRequest setProductionType() {
+ builder.getInstanceBuilder().setType(Type.PRODUCTION);
+ updateFieldMask(Instance.TYPE_FIELD_NUMBER);
+
+ return this;
+ }
+
+ /**
+ * Replaces the labels associated with the instance.
+ *
+ * @see For more
+ * details
+ */
+ @SuppressWarnings("WeakerAccess")
+ public UpdateInstanceRequest setAllLabels(@Nonnull Map labels) {
+ Preconditions.checkNotNull(labels, "labels can't be null");
+ builder.getInstanceBuilder().clearLabels();
+ builder.getInstanceBuilder().putAllLabels(labels);
+ updateFieldMask(Instance.LABELS_FIELD_NUMBER);
+
+ return this;
+ }
+
+ private void updateFieldMask(int fieldNumber) {
+ FieldMask newMask = FieldMaskUtil.fromFieldNumbers(Instance.class, fieldNumber);
+ builder.setUpdateMask(FieldMaskUtil.union(builder.getUpdateMask(), newMask));
+ }
+
+ /**
+ * Creates the request protobuf. This method is considered an internal implementation detail and
+ * not meant to be used by applications.
+ */
+ @InternalApi
+ public PartialUpdateInstanceRequest toProto(ProjectName projectName) {
+ // Empty field mask implies full resource replacement, which would clear all fields in an empty
+ // update request.
+ Preconditions.checkState(!builder.getUpdateMask().getPathsList().isEmpty(), "Update request is empty");
+
+ InstanceName instanceName = InstanceName.of(projectName.getProject(), instanceId);
+ builder.getInstanceBuilder().setName(instanceName.toString());
+
+ return builder.build();
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigtable-admin/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientTest.java b/google-cloud-clients/google-cloud-bigtable-admin/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientTest.java
index d76193b7afb5..1adbf9be0641 100644
--- a/google-cloud-clients/google-cloud-bigtable-admin/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientTest.java
+++ b/google-cloud-clients/google-cloud-bigtable-admin/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientTest.java
@@ -17,30 +17,86 @@
import static com.google.common.truth.Truth.assertThat;
+import com.google.api.core.ApiFuture;
+import com.google.api.core.ApiFutures;
+import com.google.api.gax.grpc.GrpcStatusCode;
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.api.gax.longrunning.OperationFutures;
+import com.google.api.gax.longrunning.OperationSnapshot;
+import com.google.api.gax.rpc.OperationCallable;
+import com.google.api.gax.rpc.UnaryCallable;
+import com.google.api.gax.rpc.testing.FakeOperationSnapshot;
+import com.google.bigtable.admin.v2.Cluster;
+import com.google.bigtable.admin.v2.CreateInstanceMetadata;
+import com.google.bigtable.admin.v2.Instance.Type;
+import com.google.bigtable.admin.v2.InstanceName;
+import com.google.bigtable.admin.v2.LocationName;
import com.google.bigtable.admin.v2.ProjectName;
+import com.google.bigtable.admin.v2.StorageType;
+import com.google.bigtable.admin.v2.UpdateInstanceMetadata;
+import com.google.cloud.bigtable.admin.v2.models.CreateInstanceRequest;
+import com.google.cloud.bigtable.admin.v2.models.Instance;
+import com.google.cloud.bigtable.admin.v2.models.PartialListInstancesException;
+import com.google.cloud.bigtable.admin.v2.models.UpdateInstanceRequest;
import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStub;
+import com.google.protobuf.Empty;
+import com.google.protobuf.FieldMask;
+import io.grpc.Status.Code;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
@RunWith(MockitoJUnitRunner.class)
public class BigtableInstanceAdminClientTest {
+ private static final ProjectName PROJECT_NAME = ProjectName.of("my-project");
+ private static final InstanceName INSTANCE_NAME =
+ InstanceName.of(PROJECT_NAME.getProject(), "my-instance");
+
private BigtableInstanceAdminClient adminClient;
+
@Mock
private BigtableInstanceAdminStub mockStub;
+ @Mock
+ private OperationCallable mockCreateInstanceCallable;
+
+ @Mock
+ private OperationCallable mockUpdateInstanceCallable;
+
+ @Mock
+ private UnaryCallable mockGetInstanceCallable;
+
+ @Mock
+ private UnaryCallable mockListInstancesCallable;
+
+ @Mock
+ private UnaryCallable mockDeleteInstanceCallable;
+
+
@Before
public void setUp() {
adminClient = BigtableInstanceAdminClient
- .create(ProjectName.of("[PROJECT]"), mockStub);
+ .create(PROJECT_NAME, mockStub);
+
+ Mockito.when(mockStub.createInstanceOperationCallable()).thenReturn(mockCreateInstanceCallable);
+ Mockito.when(mockStub.partialUpdateInstanceOperationCallable())
+ .thenReturn(mockUpdateInstanceCallable);
+
+ Mockito.when(mockStub.getInstanceCallable()).thenReturn(mockGetInstanceCallable);
+ Mockito.when(mockStub.listInstancesCallable()).thenReturn(mockListInstancesCallable);
+ Mockito.when(mockStub.deleteInstanceCallable()).thenReturn(mockDeleteInstanceCallable);
}
@Test
public void testProjectName() {
- assertThat(adminClient.getProjectName()).isEqualTo(ProjectName.of("[PROJECT]"));
+ assertThat(adminClient.getProjectName()).isEqualTo(PROJECT_NAME);
}
@Test
@@ -48,4 +104,216 @@ public void testClose() {
adminClient.close();
Mockito.verify(mockStub).close();
}
+
+ @Test
+ public void testCreateInstance() {
+ // Setup
+ com.google.bigtable.admin.v2.CreateInstanceRequest expectedRequest =
+ com.google.bigtable.admin.v2.CreateInstanceRequest.newBuilder()
+ .setParent(PROJECT_NAME.toString())
+ .setInstanceId(INSTANCE_NAME.getInstance())
+ .setInstance(
+ com.google.bigtable.admin.v2.Instance.newBuilder()
+ .setType(Type.DEVELOPMENT)
+ .setDisplayName(INSTANCE_NAME.getInstance())
+ )
+ .putClusters("cluster1", Cluster.newBuilder()
+ .setLocation("projects/my-project/locations/us-east1-c")
+ .setServeNodes(1)
+ .setDefaultStorageType(StorageType.SSD)
+ .build()
+ )
+ .build();
+
+ com.google.bigtable.admin.v2.Instance expectedResponse = com.google.bigtable.admin.v2.Instance
+ .newBuilder()
+ .setName(INSTANCE_NAME.toString())
+ .build();
+
+ mockOperationResult(mockCreateInstanceCallable, expectedRequest, expectedResponse);
+
+ // Execute
+ Instance actualResult = adminClient.createInstance(
+ CreateInstanceRequest.of(INSTANCE_NAME.getInstance())
+ .setType(Type.DEVELOPMENT)
+ .addCluster("cluster1", "us-east1-c", 1, StorageType.SSD)
+ );
+
+ // Verify
+ assertThat(actualResult).isEqualTo(Instance.fromProto(expectedResponse));
+ }
+
+ @Test
+ public void testUpdateInstance() {
+ // Setup
+ com.google.bigtable.admin.v2.PartialUpdateInstanceRequest expectedRequest =
+ com.google.bigtable.admin.v2.PartialUpdateInstanceRequest.newBuilder()
+ .setUpdateMask(
+ FieldMask.newBuilder()
+ .addPaths("display_name")
+ )
+ .setInstance(
+ com.google.bigtable.admin.v2.Instance.newBuilder()
+ .setName(INSTANCE_NAME.toString())
+ .setDisplayName("new display name")
+ )
+ .build();
+
+ com.google.bigtable.admin.v2.Instance expectedResponse = com.google.bigtable.admin.v2.Instance
+ .newBuilder()
+ .setName(INSTANCE_NAME.toString())
+ .build();
+
+ mockOperationResult(mockUpdateInstanceCallable, expectedRequest, expectedResponse);
+
+ // Execute
+ Instance actualResult = adminClient.updateInstance(
+ UpdateInstanceRequest.of(INSTANCE_NAME.getInstance())
+ .setDisplayName("new display name")
+ );
+
+ // Verify
+ assertThat(actualResult).isEqualTo(Instance.fromProto(expectedResponse));
+ }
+
+ @Test
+ public void testGetInstance() {
+ // Setup
+ com.google.bigtable.admin.v2.GetInstanceRequest expectedRequest =
+ com.google.bigtable.admin.v2.GetInstanceRequest.newBuilder()
+ .setName(INSTANCE_NAME.toString())
+ .build();
+
+ com.google.bigtable.admin.v2.Instance expectedResponse = com.google.bigtable.admin.v2.Instance
+ .newBuilder()
+ .setName(INSTANCE_NAME.toString())
+ .build();
+
+ Mockito.when(mockGetInstanceCallable.futureCall(expectedRequest))
+ .thenReturn(ApiFutures.immediateFuture(expectedResponse));
+
+ // Execute
+ Instance actualResult = adminClient.getInstance(INSTANCE_NAME.getInstance());
+
+ // Verify
+ assertThat(actualResult).isEqualTo(Instance.fromProto(expectedResponse));
+ }
+
+ @Test
+ public void testListInstances() {
+ // Setup
+ com.google.bigtable.admin.v2.ListInstancesRequest expectedRequest =
+ com.google.bigtable.admin.v2.ListInstancesRequest.newBuilder()
+ .setParent(PROJECT_NAME.toString())
+ .build();
+
+ com.google.bigtable.admin.v2.ListInstancesResponse expectedResponse =
+ com.google.bigtable.admin.v2.ListInstancesResponse
+ .newBuilder()
+ .addInstances(
+ com.google.bigtable.admin.v2.Instance.newBuilder().setName(INSTANCE_NAME + "1")
+ .build()
+ )
+ .addInstances(
+ com.google.bigtable.admin.v2.Instance.newBuilder().setName(INSTANCE_NAME + "2")
+ .build()
+ )
+ .build();
+
+ Mockito.when(mockListInstancesCallable.futureCall(expectedRequest))
+ .thenReturn(ApiFutures.immediateFuture(expectedResponse));
+
+ // Execute
+ List actualResult = adminClient.listInstances();
+
+ // Verify
+ assertThat(actualResult).containsExactly(
+ Instance.fromProto(expectedResponse.getInstances(0)),
+ Instance.fromProto(expectedResponse.getInstances(1))
+ );
+ }
+
+ @Test
+ public void testListInstancesFailedZone() {
+ // Setup
+ com.google.bigtable.admin.v2.ListInstancesRequest expectedRequest =
+ com.google.bigtable.admin.v2.ListInstancesRequest.newBuilder()
+ .setParent(PROJECT_NAME.toString())
+ .build();
+
+ com.google.bigtable.admin.v2.ListInstancesResponse expectedResponse =
+ com.google.bigtable.admin.v2.ListInstancesResponse
+ .newBuilder()
+ .addInstances(
+ com.google.bigtable.admin.v2.Instance.newBuilder().setName(INSTANCE_NAME + "1")
+ .build()
+ )
+ .addFailedLocations(
+ LocationName.of(PROJECT_NAME.getProject(), "us-east1-d").toString()
+ )
+ .build();
+
+ Mockito.when(mockListInstancesCallable.futureCall(expectedRequest))
+ .thenReturn(ApiFutures.immediateFuture(expectedResponse));
+
+ // Execute
+ Exception actualError = null;
+
+ try {
+ adminClient.listInstances();
+ } catch (Exception e) {
+ actualError = e;
+ }
+
+ // Verify
+ assertThat(actualError).isInstanceOf(PartialListInstancesException.class);
+ assert actualError != null;
+ PartialListInstancesException partialListError = (PartialListInstancesException) actualError;
+
+ assertThat(partialListError.getInstances())
+ .containsExactly(Instance.fromProto(expectedResponse.getInstances(0)));
+ assertThat(partialListError.getUnavailableZones()).containsExactly("us-east1-d");
+ }
+
+ @Test
+ public void testDeleteInstance() {
+ // Setup
+ com.google.bigtable.admin.v2.DeleteInstanceRequest expectedRequest =
+ com.google.bigtable.admin.v2.DeleteInstanceRequest.newBuilder()
+ .setName(INSTANCE_NAME.toString())
+ .build();
+
+ final AtomicBoolean wasCalled = new AtomicBoolean(false);
+
+ Mockito.when(mockDeleteInstanceCallable.futureCall(expectedRequest))
+ .thenAnswer(new Answer>() {
+ @Override
+ public ApiFuture answer(InvocationOnMock invocationOnMock) {
+ wasCalled.set(true);
+ return ApiFutures.immediateFuture(Empty.getDefaultInstance());
+ }
+ });
+
+ // Execute
+ adminClient.deleteInstance(INSTANCE_NAME.getInstance());
+
+ // Verify
+ assertThat(wasCalled.get()).isTrue();
+ }
+
+
+ private void mockOperationResult(
+ OperationCallable callable, ReqT request, RespT response) {
+ OperationSnapshot operationSnapshot = FakeOperationSnapshot.newBuilder()
+ .setDone(true)
+ .setErrorCode(GrpcStatusCode.of(Code.OK))
+ .setName("fake-name")
+ .setResponse(response)
+ .build();
+
+ OperationFuture operationFuture = OperationFutures
+ .immediateOperationFuture(operationSnapshot);
+
+ Mockito.when(callable.futureCall(request)).thenReturn(operationFuture);
+ }
}
diff --git a/google-cloud-clients/google-cloud-bigtable-admin/src/test/java/com/google/cloud/bigtable/admin/v2/models/CreateClusterRequestTest.java b/google-cloud-clients/google-cloud-bigtable-admin/src/test/java/com/google/cloud/bigtable/admin/v2/models/CreateClusterRequestTest.java
new file mode 100644
index 000000000000..dd0c318bd559
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigtable-admin/src/test/java/com/google/cloud/bigtable/admin/v2/models/CreateClusterRequestTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigtable.admin.v2.models;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.bigtable.admin.v2.Cluster;
+import com.google.bigtable.admin.v2.Instance;
+import com.google.bigtable.admin.v2.Instance.Type;
+import com.google.bigtable.admin.v2.ProjectName;
+import com.google.bigtable.admin.v2.StorageType;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class CreateClusterRequestTest {
+ @Test
+ public void testProductionSingle() {
+ CreateInstanceRequest input = CreateInstanceRequest.of("my-instance")
+ .setType(Type.PRODUCTION)
+ .addCluster("cluster1", "us-east1-c", 3, StorageType.SSD);
+
+ com.google.bigtable.admin.v2.CreateInstanceRequest actual = input
+ .toProto(ProjectName.of("my-project"));
+
+ com.google.bigtable.admin.v2.CreateInstanceRequest expected =
+ com.google.bigtable.admin.v2.CreateInstanceRequest.newBuilder()
+ .setParent(ProjectName.of("my-project").toString())
+ .setInstanceId("my-instance")
+ .setInstance(
+ Instance.newBuilder()
+ .setDisplayName("my-instance")
+ .setType(Type.PRODUCTION)
+ )
+ .putClusters("cluster1",
+ Cluster.newBuilder()
+ .setLocation("projects/my-project/locations/us-east1-c")
+ .setServeNodes(3)
+ .setDefaultStorageType(StorageType.SSD)
+ .build()
+ )
+ .build();
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void testProductionReplication() {
+ CreateInstanceRequest input = CreateInstanceRequest.of("my-instance")
+ .setType(Type.PRODUCTION)
+ .addCluster("cluster1", "us-east1-c", 3, StorageType.SSD)
+ .addCluster("cluster2", "us-east1-a", 3, StorageType.SSD);
+
+ com.google.bigtable.admin.v2.CreateInstanceRequest actual = input
+ .toProto(ProjectName.of("my-project"));
+
+ com.google.bigtable.admin.v2.CreateInstanceRequest expected =
+ com.google.bigtable.admin.v2.CreateInstanceRequest.newBuilder()
+ .setParent(ProjectName.of("my-project").toString())
+ .setInstanceId("my-instance")
+ .setInstance(
+ Instance.newBuilder()
+ .setDisplayName("my-instance")
+ .setType(Type.PRODUCTION)
+ )
+ .putClusters("cluster1",
+ Cluster.newBuilder()
+ .setLocation("projects/my-project/locations/us-east1-c")
+ .setServeNodes(3)
+ .setDefaultStorageType(StorageType.SSD)
+ .build()
+ )
+ .putClusters("cluster2",
+ Cluster.newBuilder()
+ .setLocation("projects/my-project/locations/us-east1-a")
+ .setServeNodes(3)
+ .setDefaultStorageType(StorageType.SSD)
+ .build()
+ )
+ .build();
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void testDevelopment() {
+ CreateInstanceRequest input = CreateInstanceRequest.of("my-instance")
+ .setType(Type.DEVELOPMENT)
+ .addCluster("cluster1", "us-east1-c", 1, StorageType.SSD);
+
+ com.google.bigtable.admin.v2.CreateInstanceRequest actual = input
+ .toProto(ProjectName.of("my-project"));
+
+ com.google.bigtable.admin.v2.CreateInstanceRequest expected =
+ com.google.bigtable.admin.v2.CreateInstanceRequest.newBuilder()
+ .setParent(ProjectName.of("my-project").toString())
+ .setInstanceId("my-instance")
+ .setInstance(
+ Instance.newBuilder()
+ .setDisplayName("my-instance")
+ .setType(Type.DEVELOPMENT)
+ )
+ .putClusters("cluster1",
+ Cluster.newBuilder()
+ .setLocation("projects/my-project/locations/us-east1-c")
+ .setServeNodes(1)
+ .setDefaultStorageType(StorageType.SSD)
+ .build()
+ )
+ .build();
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void testOptionalFields() {
+ CreateInstanceRequest input = CreateInstanceRequest.of("my-instance")
+ .setDisplayName("custom display name")
+ .addLabel("my label", "with some value")
+ .addLabel("my other label", "with some value")
+ .setType(Type.DEVELOPMENT)
+ .addCluster("cluster1", "us-east1-c", 1, StorageType.SSD);
+
+ com.google.bigtable.admin.v2.CreateInstanceRequest actual = input
+ .toProto(ProjectName.of("my-project"));
+
+ com.google.bigtable.admin.v2.CreateInstanceRequest expected =
+ com.google.bigtable.admin.v2.CreateInstanceRequest.newBuilder()
+ .setParent(ProjectName.of("my-project").toString())
+ .setInstanceId("my-instance")
+ .setInstance(
+ Instance.newBuilder()
+ .setDisplayName("custom display name")
+ .putLabels("my label", "with some value")
+ .putLabels("my other label", "with some value")
+ .setType(Type.DEVELOPMENT)
+ )
+ .putClusters("cluster1",
+ Cluster.newBuilder()
+ .setLocation("projects/my-project/locations/us-east1-c")
+ .setServeNodes(1)
+ .setDefaultStorageType(StorageType.SSD)
+ .build()
+ )
+ .build();
+
+ assertThat(actual).isEqualTo(expected);
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigtable-admin/src/test/java/com/google/cloud/bigtable/admin/v2/models/InstanceTest.java b/google-cloud-clients/google-cloud-bigtable-admin/src/test/java/com/google/cloud/bigtable/admin/v2/models/InstanceTest.java
new file mode 100644
index 000000000000..3d63bab16d0c
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigtable-admin/src/test/java/com/google/cloud/bigtable/admin/v2/models/InstanceTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigtable.admin.v2.models;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.bigtable.admin.v2.Instance.State;
+import com.google.bigtable.admin.v2.Instance.Type;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class InstanceTest {
+ @Test
+ public void testFromProto() {
+ com.google.bigtable.admin.v2.Instance proto = com.google.bigtable.admin.v2.Instance.newBuilder()
+ .setName("projects/my-project/instances/my-instance")
+ .setDisplayName("my display name")
+ .setType(Type.PRODUCTION)
+ .setState(State.READY)
+ .putLabels("label1", "value1")
+ .putLabels("label2", "value2")
+ .build();
+
+ Instance result = Instance.fromProto(proto);
+
+ assertThat(result.getId()).isEqualTo("my-instance");
+ assertThat(result.getDisplayName()).isEqualTo("my display name");
+ assertThat(result.getType()).isEqualTo(Type.PRODUCTION);
+ assertThat(result.getState()).isEqualTo(State.READY);
+ assertThat(result.getLabels()).containsExactly(
+ "label1", "value1",
+ "label2", "value2"
+ );
+ }
+
+ @Test
+ public void testRequiresName() {
+ com.google.bigtable.admin.v2.Instance proto = com.google.bigtable.admin.v2.Instance.newBuilder()
+ .setDisplayName("my display name")
+ .setType(Type.PRODUCTION)
+ .setState(State.READY)
+ .putLabels("label1", "value1")
+ .putLabels("label2", "value2")
+ .build();
+
+ Exception actualException = null;
+
+ try {
+ Instance.fromProto(proto);
+ } catch (Exception e) {
+ actualException = e;
+ }
+
+ assertThat(actualException).isInstanceOf(IllegalArgumentException.class);
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigtable-admin/src/test/java/com/google/cloud/bigtable/admin/v2/models/UpdateInstanceRequestTest.java b/google-cloud-clients/google-cloud-bigtable-admin/src/test/java/com/google/cloud/bigtable/admin/v2/models/UpdateInstanceRequestTest.java
new file mode 100644
index 000000000000..b44464fa0918
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigtable-admin/src/test/java/com/google/cloud/bigtable/admin/v2/models/UpdateInstanceRequestTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigtable.admin.v2.models;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.bigtable.admin.v2.Instance;
+import com.google.bigtable.admin.v2.Instance.Type;
+import com.google.bigtable.admin.v2.PartialUpdateInstanceRequest;
+import com.google.bigtable.admin.v2.ProjectName;
+import com.google.common.collect.ImmutableMap;
+import com.google.protobuf.FieldMask;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class UpdateInstanceRequestTest {
+ @Test
+ public void testEmpty() {
+ UpdateInstanceRequest input = UpdateInstanceRequest.of("my-instance");
+
+ Exception actualError = null;
+
+ try {
+ input.toProto(ProjectName.of("my-project"));
+ } catch (Exception e) {
+ actualError = e;
+ }
+
+ assertThat(actualError).isInstanceOf(IllegalStateException.class);
+ }
+
+ @Test
+ public void testDisplayName() {
+ UpdateInstanceRequest input = UpdateInstanceRequest.of("my-instance")
+ .setDisplayName("my display name");
+
+ PartialUpdateInstanceRequest actual = input.toProto(ProjectName.of("my-project"));
+
+ PartialUpdateInstanceRequest expected = PartialUpdateInstanceRequest.newBuilder()
+ .setUpdateMask(
+ FieldMask.newBuilder()
+ .addPaths("display_name")
+ )
+ .setInstance(
+ Instance.newBuilder()
+ .setName("projects/my-project/instances/my-instance")
+ .setDisplayName("my display name")
+ )
+ .build();
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void testLabels() {
+ UpdateInstanceRequest input = UpdateInstanceRequest.of("my-instance")
+ .setAllLabels(ImmutableMap.of(
+ "label1", "value1",
+ "label2", "value2"
+ ));
+
+ PartialUpdateInstanceRequest actual = input.toProto(ProjectName.of("my-project"));
+
+ PartialUpdateInstanceRequest expected = PartialUpdateInstanceRequest.newBuilder()
+ .setUpdateMask(
+ FieldMask.newBuilder()
+ .addPaths("labels")
+ )
+ .setInstance(
+ Instance.newBuilder()
+ .setName("projects/my-project/instances/my-instance")
+ .putLabels("label1", "value1")
+ .putLabels("label2", "value2")
+ )
+ .build();
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void testType() {
+ UpdateInstanceRequest input = UpdateInstanceRequest.of("my-instance")
+ .setProductionType();
+
+ PartialUpdateInstanceRequest actual = input.toProto(ProjectName.of("my-project"));
+
+ PartialUpdateInstanceRequest expected = PartialUpdateInstanceRequest.newBuilder()
+ .setUpdateMask(
+ FieldMask.newBuilder()
+ .addPaths("type")
+ )
+ .setInstance(
+ Instance.newBuilder()
+ .setName("projects/my-project/instances/my-instance")
+ .setType(Type.PRODUCTION)
+ )
+ .build();
+
+ assertThat(actual).isEqualTo(expected);
+ }
+}