diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Compute.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Compute.java
index dbc2f0d49366..ee0c327da8dc 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Compute.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Compute.java
@@ -963,6 +963,88 @@ public static DiskFilter notEquals(DiskField field, long value) {
}
}
+ /**
+ * Class for filtering subnetwork lists.
+ */
+ class SubnetworkFilter extends ListFilter {
+
+ private static final long serialVersionUID = 979448583739105481L;
+
+ private SubnetworkFilter(SubnetworkField field, ComparisonOperator operator, Object value) {
+ super(field.selector(), operator, value);
+ }
+
+ /**
+ * Returns an equals filter for the given field and string value. For string fields,
+ * {@code value} is interpreted as a regular expression using RE2 syntax. {@code value} must
+ * match the entire field.
+ *
+ * @see RE2
+ */
+ public static SubnetworkFilter equals(SubnetworkField field, String value) {
+ return new SubnetworkFilter(checkNotNull(field), ComparisonOperator.EQ, checkNotNull(value));
+ }
+
+ /**
+ * Returns a not-equals filter for the given field and string value. For string fields,
+ * {@code value} is interpreted as a regular expression using RE2 syntax. {@code value} must
+ * match the entire field.
+ *
+ * @see RE2
+ */
+ public static SubnetworkFilter notEquals(SubnetworkField field, String value) {
+ return new SubnetworkFilter(checkNotNull(field), ComparisonOperator.NE, checkNotNull(value));
+ }
+ }
+
+ /**
+ * Class for filtering network lists.
+ */
+ class NetworkFilter extends ListFilter {
+
+ private static final long serialVersionUID = 7921406498804130930L;
+
+ private NetworkFilter(NetworkField field, ComparisonOperator operator, Object value) {
+ super(field.selector(), operator, value);
+ }
+
+ /**
+ * Returns an equals filter for the given field and string value. For string fields,
+ * {@code value} is interpreted as a regular expression using RE2 syntax. {@code value} must
+ * match the entire field.
+ *
+ * @see RE2
+ */
+ public static NetworkFilter equals(NetworkField field, String value) {
+ return new NetworkFilter(checkNotNull(field), ComparisonOperator.EQ, checkNotNull(value));
+ }
+
+ /**
+ * Returns a not-equals filter for the given field and string value. For string fields,
+ * {@code value} is interpreted as a regular expression using RE2 syntax. {@code value} must
+ * match the entire field.
+ *
+ * @see RE2
+ */
+ public static NetworkFilter notEquals(NetworkField field, String value) {
+ return new NetworkFilter(checkNotNull(field), ComparisonOperator.NE, checkNotNull(value));
+ }
+
+ /**
+ * Returns a equals filter for the given field and boolean value.
+ */
+ public static NetworkFilter equals(NetworkField field, boolean value) {
+ return new NetworkFilter(checkNotNull(field), ComparisonOperator.EQ, value);
+ }
+
+ /**
+ * Returns a not-equals filter for the given field and boolean value.
+ */
+ public static NetworkFilter notEquals(NetworkField field, boolean value) {
+ return new NetworkFilter(checkNotNull(field), ComparisonOperator.NE, value);
+ }
+ }
+
/**
* Class for specifying disk type get options.
*/
@@ -1737,6 +1819,176 @@ public static DiskAggregatedListOption pageToken(String pageToken) {
}
}
+ /**
+ * Class for specifying subnetwork get options.
+ */
+ class SubnetworkOption extends Option {
+
+ private static final long serialVersionUID = 1994416967962074717L;
+
+ private SubnetworkOption(ComputeRpc.Option option, Object value) {
+ super(option, value);
+ }
+
+ /**
+ * Returns an option to specify the subnetwork's fields to be returned by the RPC call. If this
+ * option is not provided, all subnetwork's fields are returned. {@code SubnetworkOption.fields}
+ * can be used to specify only the fields of interest. {@link Subnetwork#subnetworkId()} is
+ * always returned, even if not specified.
+ */
+ public static SubnetworkOption fields(SubnetworkField... fields) {
+ return new SubnetworkOption(ComputeRpc.Option.FIELDS, SubnetworkField.selector(fields));
+ }
+ }
+
+ /**
+ * Class for specifying subnetwork list options.
+ */
+ class SubnetworkListOption extends Option {
+
+ private static final long serialVersionUID = -2978666213373829606L;
+
+ private SubnetworkListOption(ComputeRpc.Option option, Object value) {
+ super(option, value);
+ }
+
+ /**
+ * Returns an option to specify a filter on the subnetworks being listed.
+ */
+ public static SubnetworkListOption filter(SubnetworkFilter filter) {
+ return new SubnetworkListOption(ComputeRpc.Option.FILTER, filter.toPb());
+ }
+
+ /**
+ * Returns an option to specify the maximum number of subnetworks returned per page.
+ * {@code pageSize} must be between 0 and 500 (inclusive). If not specified 500 is used.
+ */
+ public static SubnetworkListOption pageSize(long pageSize) {
+ return new SubnetworkListOption(ComputeRpc.Option.MAX_RESULTS, pageSize);
+ }
+
+ /**
+ * Returns an option to specify the page token from which to start listing subnetworks.
+ */
+ public static SubnetworkListOption pageToken(String pageToken) {
+ return new SubnetworkListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken);
+ }
+
+ /**
+ * Returns an option to specify the subnetwork's fields to be returned by the RPC call. If this
+ * option is not provided, all subnetwork's fields are returned.
+ * {@code SubnetworListkOption.fields} can be used to specify only the fields of interest.
+ * {@link Subnetwork#subnetworkId()} is always returned, even if not specified.
+ */
+ public static SubnetworkListOption fields(SubnetworkField... fields) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("items(").append(SubnetworkField.selector(fields)).append("),nextPageToken");
+ return new SubnetworkListOption(ComputeRpc.Option.FIELDS, builder.toString());
+ }
+ }
+
+ /**
+ * Class for specifying subnetwork aggregated list options.
+ */
+ class SubnetworkAggregatedListOption extends Option {
+
+ private static final long serialVersionUID = -4033514850525545027L;
+
+ private SubnetworkAggregatedListOption(ComputeRpc.Option option, Object value) {
+ super(option, value);
+ }
+
+ /**
+ * Returns an option to specify a filter on the subnetworks being listed.
+ */
+ public static SubnetworkAggregatedListOption filter(SubnetworkFilter filter) {
+ return new SubnetworkAggregatedListOption(ComputeRpc.Option.FILTER, filter.toPb());
+ }
+
+ /**
+ * Returns an option to specify the maximum number of subnetworks returned per page.
+ * {@code pageSize} must be between 0 and 500 (inclusive). If not specified 500 is used.
+ */
+ public static SubnetworkAggregatedListOption pageSize(long pageSize) {
+ return new SubnetworkAggregatedListOption(ComputeRpc.Option.MAX_RESULTS, pageSize);
+ }
+
+ /**
+ * Returns an option to specify the page token from which to start listing subnetworks.
+ */
+ public static SubnetworkAggregatedListOption pageToken(String pageToken) {
+ return new SubnetworkAggregatedListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken);
+ }
+ }
+
+ /**
+ * Class for specifying network get options.
+ */
+ class NetworkOption extends Option {
+
+ private static final long serialVersionUID = 5346750551643875754L;
+
+ private NetworkOption(ComputeRpc.Option option, Object value) {
+ super(option, value);
+ }
+
+ /**
+ * Returns an option to specify the network's fields to be returned by the RPC call. If this
+ * option is not provided, all network's fields are returned. {@code NetworkOption.fields}
+ * can be used to specify only the fields of interest. {@link Network#networkId()} and
+ * {@link Network#configuration()} are always returned, even if not specified.
+ */
+ public static NetworkOption fields(NetworkField... fields) {
+ return new NetworkOption(ComputeRpc.Option.FIELDS, NetworkField.selector(fields));
+ }
+ }
+
+ /**
+ * Class for specifying network list options.
+ */
+ class NetworkListOption extends Option {
+
+ private static final long serialVersionUID = -4291731916527773896L;
+
+ private NetworkListOption(ComputeRpc.Option option, Object value) {
+ super(option, value);
+ }
+
+ /**
+ * Returns an option to specify a filter on the networks being listed.
+ */
+ public static NetworkListOption filter(NetworkFilter filter) {
+ return new NetworkListOption(ComputeRpc.Option.FILTER, filter.toPb());
+ }
+
+ /**
+ * Returns an option to specify the maximum number of networks returned per page.
+ * {@code pageSize} must be between 0 and 500 (inclusive). If not specified 500 is used.
+ */
+ public static NetworkListOption pageSize(long pageSize) {
+ return new NetworkListOption(ComputeRpc.Option.MAX_RESULTS, pageSize);
+ }
+
+ /**
+ * Returns an option to specify the page token from which to start listing networks.
+ */
+ public static NetworkListOption pageToken(String pageToken) {
+ return new NetworkListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken);
+ }
+
+ /**
+ * Returns an option to specify the network's fields to be returned by the RPC call. If this
+ * option is not provided, all network's fields are returned. {@code NetworkListOption.fields}
+ * can be used to specify only the fields of interest. {@link Network#networkId()} and
+ * {@link Network#configuration()} are always returned, even if not specified.
+ */
+ public static NetworkListOption fields(NetworkField... fields) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("items(").append(NetworkField.selector(fields)).append("),nextPageToken");
+ return new NetworkListOption(ComputeRpc.Option.FIELDS, builder.toString());
+ }
+ }
+
/**
* Returns the requested disk type or {@code null} if not found.
*
@@ -2066,4 +2318,83 @@ Operation deprecate(ImageId image, DeprecationStatus deprecationStatus,
* @throws ComputeException upon failure or if the new disk size is smaller than the previous one
*/
Operation resize(DiskId disk, long sizeGb, OperationOption... options);
+
+ /*
+ * Creates a new subnetwork.
+ *
+ * @return a region operation for subnetwork's creation
+ * @throws ComputeException upon failure
+ */
+ Operation create(SubnetworkInfo subnetwork, OperationOption... options);
+
+ /**
+ * Returns the requested subnetwork or {@code null} if not found.
+ *
+ * @throws ComputeException upon failure
+ */
+ Subnetwork get(SubnetworkId subnetworkId, SubnetworkOption... options);
+
+ /**
+ * Lists subnetworks for the provided region.
+ *
+ * @throws ComputeException upon failure
+ */
+ Page listSubnetworks(String project, SubnetworkListOption... options);
+
+ /**
+ * Lists subnetworks for all regions.
+ *
+ * @throws ComputeException upon failure
+ */
+ Page listSubnetworks(SubnetworkAggregatedListOption... options);
+
+ /**
+ * Deletes the requested subnetwork. Any attempt to delete an automatically created subnetwork
+ * will fail.
+ *
+ * @return a region operation if the delete request was issued correctly, {@code null} if the
+ * subnetwork was not found
+ * @throws ComputeException upon failure
+ */
+ Operation delete(SubnetworkId subnetwork, OperationOption... options);
+
+ /**
+ * Creates a new network.
+ *
+ * @return a global operation for network's creation
+ * @throws ComputeException upon failure
+ */
+ Operation create(NetworkInfo network, OperationOption... options);
+
+ /**
+ * Returns the requested network or {@code null} if not found.
+ *
+ * @throws ComputeException upon failure
+ */
+ Network getNetwork(String network, NetworkOption... options);
+
+ /**
+ * Lists networks.
+ *
+ * @throws ComputeException upon failure
+ */
+ Page listNetworks(NetworkListOption... options);
+
+ /**
+ * Deletes the requested network.
+ *
+ * @return a global operation if the delete request was issued correctly, {@code null} if the
+ * network was not found
+ * @throws ComputeException upon failure
+ */
+ Operation deleteNetwork(String network, OperationOption... options);
+
+ /**
+ * Deletes the requested network.
+ *
+ * @return a global operation if the delete request was issued correctly, {@code null} if the
+ * network was not found
+ * @throws ComputeException upon failure
+ */
+ Operation deleteNetwork(NetworkId network, OperationOption... options);
}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ComputeImpl.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ComputeImpl.java
index f453d0768e13..f19b6ee641a1 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ComputeImpl.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ComputeImpl.java
@@ -353,6 +353,65 @@ public Page nextPage() {
}
}
+ private static class SubnetworkPageFetcher implements NextPageFetcher {
+
+ private static final long serialVersionUID = 3674038457884412651L;
+ private final Map requestOptions;
+ private final ComputeOptions serviceOptions;
+ private final String region;
+
+ SubnetworkPageFetcher(String region, ComputeOptions serviceOptions, String cursor,
+ Map optionMap) {
+ this.requestOptions =
+ PageImpl.nextRequestOptions(ComputeRpc.Option.PAGE_TOKEN, cursor, optionMap);
+ this.serviceOptions = serviceOptions;
+ this.region = region;
+ }
+
+ @Override
+ public Page nextPage() {
+ return listSubnetworks(region, serviceOptions, requestOptions);
+ }
+ }
+
+ private static class AggregatedSubnetworkPageFetcher implements NextPageFetcher {
+
+ private static final long serialVersionUID = 771343548833894551L;
+ private final Map requestOptions;
+ private final ComputeOptions serviceOptions;
+
+ AggregatedSubnetworkPageFetcher(ComputeOptions serviceOptions, String cursor,
+ Map optionMap) {
+ this.requestOptions =
+ PageImpl.nextRequestOptions(ComputeRpc.Option.PAGE_TOKEN, cursor, optionMap);
+ this.serviceOptions = serviceOptions;
+ }
+
+ @Override
+ public Page nextPage() {
+ return listSubnetworks(serviceOptions, requestOptions);
+ }
+ }
+
+ private static class NetworkPageFetcher implements NextPageFetcher {
+
+ private static final long serialVersionUID = 5580210850353114531L;
+ private final Map requestOptions;
+ private final ComputeOptions serviceOptions;
+
+ NetworkPageFetcher(ComputeOptions serviceOptions, String cursor,
+ Map optionMap) {
+ this.requestOptions =
+ PageImpl.nextRequestOptions(ComputeRpc.Option.PAGE_TOKEN, cursor, optionMap);
+ this.serviceOptions = serviceOptions;
+ }
+
+ @Override
+ public Page nextPage() {
+ return listNetworks(serviceOptions, requestOptions);
+ }
+ }
+
private final ComputeRpc computeRpc;
ComputeImpl(ComputeOptions options) {
@@ -1336,6 +1395,217 @@ public com.google.api.services.compute.model.Operation call() {
}
}
+ public Operation create(SubnetworkInfo subnetwork, OperationOption... options) {
+ final SubnetworkInfo completeSubnetwork = subnetwork.setProjectId(options().projectId());
+ final Map optionsMap = optionMap(options);
+ try {
+ com.google.api.services.compute.model.Operation answer =
+ runWithRetries(new Callable() {
+ @Override
+ public com.google.api.services.compute.model.Operation call() {
+ return computeRpc.createSubnetwork(completeSubnetwork.subnetworkId().region(),
+ completeSubnetwork.toPb(), optionsMap);
+ }
+ }, options().retryParams(), EXCEPTION_HANDLER);
+ return answer == null ? null : Operation.fromPb(this, answer);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public Subnetwork get(final SubnetworkId subnetworkId, SubnetworkOption... options) {
+ final Map optionsMap = optionMap(options);
+ try {
+ com.google.api.services.compute.model.Subnetwork answer =
+ runWithRetries(new Callable() {
+ @Override
+ public com.google.api.services.compute.model.Subnetwork call() {
+ return computeRpc.getSubnetwork(subnetworkId.region(), subnetworkId.subnetwork(),
+ optionsMap);
+ }
+ }, options().retryParams(), EXCEPTION_HANDLER);
+ return answer == null ? null : Subnetwork.fromPb(this, answer);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ private static Function
+ subnetworkFromPb(final ComputeOptions serviceOptions) {
+ return new Function() {
+ @Override
+ public Subnetwork apply(com.google.api.services.compute.model.Subnetwork subnetwork) {
+ return Subnetwork.fromPb(serviceOptions.service(), subnetwork);
+ }
+ };
+ }
+
+ @Override
+ public Page listSubnetworks(String region, SubnetworkListOption... options) {
+ return listSubnetworks(region, options(), optionMap(options));
+ }
+
+ private static Page listSubnetworks(final String region,
+ final ComputeOptions serviceOptions, final Map optionsMap) {
+ try {
+ ComputeRpc.Tuple> result =
+ runWithRetries(new Callable>>() {
+ @Override
+ public ComputeRpc.Tuple> call() {
+ return serviceOptions.rpc().listSubnetworks(region, optionsMap);
+ }
+ }, serviceOptions.retryParams(), EXCEPTION_HANDLER);
+ String cursor = result.x();
+ Iterable subnetworks = Iterables.transform(
+ result.y() == null ? ImmutableList.of()
+ : result.y(), subnetworkFromPb(serviceOptions));
+ return new PageImpl<>(new SubnetworkPageFetcher(region, serviceOptions, cursor, optionsMap),
+ cursor, subnetworks);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public Page listSubnetworks(SubnetworkAggregatedListOption... options) {
+ return listSubnetworks(options(), optionMap(options));
+ }
+
+ private static Page listSubnetworks(final ComputeOptions serviceOptions,
+ final Map optionsMap) {
+ try {
+ ComputeRpc.Tuple> result =
+ runWithRetries(new Callable>>() {
+ @Override
+ public ComputeRpc.Tuple> call() {
+ return serviceOptions.rpc().listSubnetworks(optionsMap);
+ }
+ }, serviceOptions.retryParams(), EXCEPTION_HANDLER);
+ String cursor = result.x();
+ Iterable subnetworks = Iterables.transform(
+ result.y() == null ? ImmutableList.of()
+ : result.y(), subnetworkFromPb(serviceOptions));
+ return new PageImpl<>(new AggregatedSubnetworkPageFetcher(serviceOptions, cursor, optionsMap),
+ cursor, subnetworks);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public Operation delete(final SubnetworkId subnetwork, OperationOption... options) {
+ final Map optionsMap = optionMap(options);
+ try {
+ com.google.api.services.compute.model.Operation answer =
+ runWithRetries(new Callable() {
+ @Override
+ public com.google.api.services.compute.model.Operation call() {
+ return computeRpc.deleteSubnetwork(subnetwork.region(), subnetwork.subnetwork(),
+ optionsMap);
+ }
+ }, options().retryParams(), EXCEPTION_HANDLER);
+ return answer == null ? null : Operation.fromPb(this, answer);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public Operation create(NetworkInfo network, OperationOption... options) {
+ final NetworkInfo completeNetwork = network.setProjectId(options().projectId());
+ final Map optionsMap = optionMap(options);
+ try {
+ com.google.api.services.compute.model.Operation answer =
+ runWithRetries(new Callable() {
+ @Override
+ public com.google.api.services.compute.model.Operation call() {
+ return computeRpc.createNetwork(completeNetwork.toPb(), optionsMap);
+ }
+ }, options().retryParams(), EXCEPTION_HANDLER);
+ return answer == null ? null : Operation.fromPb(this, answer);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public Network getNetwork(final String network, NetworkOption... options) {
+ final Map optionsMap = optionMap(options);
+ try {
+ com.google.api.services.compute.model.Network answer =
+ runWithRetries(new Callable() {
+ @Override
+ public com.google.api.services.compute.model.Network call() {
+ return computeRpc.getNetwork(network, optionsMap);
+ }
+ }, options().retryParams(), EXCEPTION_HANDLER);
+ return answer == null ? null : Network.fromPb(this, answer);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public Page listNetworks(NetworkListOption... options) {
+ return listNetworks(options(), optionMap(options));
+ }
+
+ private static Page listNetworks(final ComputeOptions serviceOptions,
+ final Map optionsMap) {
+ try {
+ ComputeRpc.Tuple> result =
+ runWithRetries(new Callable>>() {
+ @Override
+ public ComputeRpc.Tuple> call() {
+ return serviceOptions.rpc().listNetworks(optionsMap);
+ }
+ }, serviceOptions.retryParams(), EXCEPTION_HANDLER);
+ String cursor = result.x();
+ Iterable networks = Iterables.transform(
+ result.y() == null ? ImmutableList.of()
+ : result.y(),
+ new Function() {
+ @Override
+ public Network apply(com.google.api.services.compute.model.Network network) {
+ return Network.fromPb(serviceOptions.service(), network);
+ }
+ });
+ return new PageImpl<>(new NetworkPageFetcher(serviceOptions, cursor, optionsMap),
+ cursor, networks);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public Operation deleteNetwork(final NetworkId network, OperationOption... options) {
+ final Map optionsMap = optionMap(options);
+ try {
+ com.google.api.services.compute.model.Operation answer =
+ runWithRetries(new Callable() {
+ @Override
+ public com.google.api.services.compute.model.Operation call() {
+ return computeRpc.deleteNetwork(network.network(), optionsMap);
+ }
+ }, options().retryParams(), EXCEPTION_HANDLER);
+ return answer == null ? null : Operation.fromPb(this, answer);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public Operation deleteNetwork(String network, OperationOption... options) {
+ return deleteNetwork(NetworkId.of(network));
+ }
+
private Map optionMap(Option... options) {
Map optionMap = Maps.newEnumMap(ComputeRpc.Option.class);
for (Option option : options) {
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Network.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Network.java
new file mode 100644
index 000000000000..f438f2b8d3df
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Network.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * 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
+ *
+ * http://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.gcloud.compute;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.gcloud.compute.Compute.NetworkOption;
+import com.google.gcloud.compute.Compute.OperationOption;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Objects;
+
+/**
+ * A Google Compute Engine Network. Every virtual machine instance is created as a member of a
+ * network. Networks connect instances to each other and to the Internet. You can segment your
+ * networks, use firewall rules to restrict access to instances, and create static routes to forward
+ * traffic to specific destinations. Objects of this class are immutable. To get a {@code Network}
+ * object with the most recent information use {@link #reload}. {@code Network} adds a layer of
+ * service-related functionality over {@link NetworkInfo}.
+ *
+ * @see Using Networks and Firewalls
+ */
+public class Network extends NetworkInfo {
+
+ private static final long serialVersionUID = 8608280908101278096L;
+
+ private final ComputeOptions options;
+ private transient Compute compute;
+
+ /**
+ * A builder for {@code Network} objects.
+ */
+ public static class Builder extends NetworkInfo.Builder {
+
+ private final Compute compute;
+ private final NetworkInfo.BuilderImpl infoBuilder;
+
+ Builder(Compute compute, NetworkId networkId, NetworkConfiguration configuration) {
+ this.compute = compute;
+ this.infoBuilder = new NetworkInfo.BuilderImpl(networkId, configuration);
+ this.infoBuilder.networkId(networkId);
+ this.infoBuilder.configuration(configuration);
+ }
+
+ Builder(Network subnetwork) {
+ this.compute = subnetwork.compute;
+ this.infoBuilder = new NetworkInfo.BuilderImpl(subnetwork);
+ }
+
+ @Override
+ Builder id(String id) {
+ infoBuilder.id(id);
+ return this;
+ }
+
+ @Override
+ Builder creationTimestamp(Long creationTimestamp) {
+ infoBuilder.creationTimestamp(creationTimestamp);
+ return this;
+ }
+
+ @Override
+ public Builder networkId(NetworkId networkId) {
+ infoBuilder.networkId(networkId);
+ return this;
+ }
+
+ @Override
+ public Builder description(String description) {
+ infoBuilder.description(description);
+ return this;
+ }
+
+ @Override
+ public Builder configuration(NetworkConfiguration configuration) {
+ infoBuilder.configuration(configuration);
+ return this;
+ }
+
+ @Override
+ public Network build() {
+ return new Network(compute, infoBuilder);
+ }
+ }
+
+ Network(Compute compute, NetworkInfo.BuilderImpl infoBuilder) {
+ super(infoBuilder);
+ this.compute = checkNotNull(compute);
+ this.options = compute.options();
+ }
+
+ /**
+ * Checks if this network exists.
+ *
+ * @return {@code true} if this network exists, {@code false} otherwise
+ * @throws ComputeException upon failure
+ */
+ public boolean exists() {
+ return reload(NetworkOption.fields()) != null;
+ }
+
+ /**
+ * Fetches current network' latest information. Returns {@code null} if the network does not
+ * exist.
+ *
+ * @param options network options
+ * @return a {@code Network} object with latest information or {@code null} if not found
+ * @throws ComputeException upon failure
+ */
+ public Network reload(NetworkOption... options) {
+ return compute.getNetwork(networkId().network(), options);
+ }
+
+ /**
+ * Deletes this network.
+ *
+ * @return an operation object if delete request was successfully sent, {@code null} if the
+ * network was not found
+ * @throws ComputeException upon failure
+ */
+ public Operation delete(OperationOption... options) {
+ return compute.deleteNetwork(networkId().network(), options);
+ }
+
+ /**
+ * Creates a subnetwork for this network given its identity and the range of IPv4 addresses in
+ * CIDR format. Subnetwork creation is only supported for networks in "custom subnet mode" (i.e.
+ * {@link #configuration()} returns a {@link SubnetNetworkConfiguration}) with automatic creation
+ * of subnetworks disabled (i.e. {@link SubnetNetworkConfiguration#autoCreateSubnetworks()}
+ * returns {@code false}).
+ *
+ * @return an operation object if creation request was successfully sent
+ * @throws ComputeException upon failure
+ * @see CIDR
+ */
+ public Operation createSubnetwork(SubnetworkId subnetworkId, String ipRange,
+ OperationOption... options) {
+ return compute.create(SubnetworkInfo.of(subnetworkId, networkId(), ipRange), options);
+ }
+
+ /**
+ * Returns the network's {@code Compute} object used to issue requests.
+ */
+ public Compute compute() {
+ return compute;
+ }
+
+ @Override
+ public Builder toBuilder() {
+ return new Builder(this);
+ }
+
+ @Override
+ public final boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj == null || !obj.getClass().equals(Network.class)) {
+ return false;
+ }
+ Network other = (Network) obj;
+ return Objects.equals(toPb(), other.toPb()) && Objects.equals(options, other.options);
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(super.hashCode(), options);
+ }
+
+ private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException {
+ input.defaultReadObject();
+ this.compute = options.service();
+ }
+
+ static Network fromPb(Compute compute,
+ com.google.api.services.compute.model.Network networkPb) {
+ return new Network(compute, new NetworkInfo.BuilderImpl(networkPb));
+ }
+}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Subnetwork.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Subnetwork.java
new file mode 100644
index 000000000000..6a42d8663ea3
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Subnetwork.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * 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
+ *
+ * http://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.gcloud.compute;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.gcloud.compute.Compute.OperationOption;
+import com.google.gcloud.compute.Compute.SubnetworkOption;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Objects;
+
+/**
+ * A Google Compute Engine Subnetwork. Subnetworks segments your cloud network IP space into
+ * subnetworks. Subnetwork prefixes can be automatically allocated, or you can create a custom
+ * topology. Objects of this class are immutable. To get a {@code Subnetwork} object with the most
+ * recent information use {@link #reload}. {@code Subnetwork} adds a layer of service-related
+ * functionality over {@link SubnetworkInfo}.
+ *
+ * @see Subnetworks
+ */
+public class Subnetwork extends SubnetworkInfo {
+
+ private static final long serialVersionUID = 8608280908101278096L;
+
+ private final ComputeOptions options;
+ private transient Compute compute;
+
+ /**
+ * A builder for {@code Subnetwork} objects.
+ */
+ public static class Builder extends SubnetworkInfo.Builder {
+
+ private final Compute compute;
+ private final SubnetworkInfo.BuilderImpl infoBuilder;
+
+ Builder(Compute compute, SubnetworkId subnetworkId, NetworkId networkId, String ipRange) {
+ this.compute = compute;
+ this.infoBuilder = new SubnetworkInfo.BuilderImpl(subnetworkId, networkId, ipRange);
+ this.infoBuilder.subnetworkId(subnetworkId);
+ this.infoBuilder.network(networkId);
+ this.infoBuilder.ipRange(ipRange);
+ }
+
+ Builder(Subnetwork subnetwork) {
+ this.compute = subnetwork.compute;
+ this.infoBuilder = new SubnetworkInfo.BuilderImpl(subnetwork);
+ }
+
+ @Override
+ Builder id(String id) {
+ infoBuilder.id(id);
+ return this;
+ }
+
+ @Override
+ Builder creationTimestamp(Long creationTimestamp) {
+ infoBuilder.creationTimestamp(creationTimestamp);
+ return this;
+ }
+
+ @Override
+ public Builder subnetworkId(SubnetworkId subnetworkId) {
+ infoBuilder.subnetworkId(subnetworkId);
+ return this;
+ }
+
+ @Override
+ public Builder description(String description) {
+ infoBuilder.description(description);
+ return this;
+ }
+
+ @Override
+ Builder gatewayAddress(String gatewayAddress) {
+ infoBuilder.gatewayAddress(gatewayAddress);
+ return this;
+ }
+
+ @Override
+ public Builder network(NetworkId network) {
+ infoBuilder.network(network);
+ return this;
+ }
+
+ @Override
+ public Builder ipRange(String ipRange) {
+ infoBuilder.ipRange(ipRange);
+ return this;
+ }
+
+ @Override
+ public Subnetwork build() {
+ return new Subnetwork(compute, infoBuilder);
+ }
+ }
+
+ Subnetwork(Compute compute, SubnetworkInfo.BuilderImpl infoBuilder) {
+ super(infoBuilder);
+ this.compute = checkNotNull(compute);
+ this.options = compute.options();
+ }
+
+ /**
+ * Checks if this subnetwork exists.
+ *
+ * @return {@code true} if this subnetwork exists, {@code false} otherwise
+ * @throws ComputeException upon failure
+ */
+ public boolean exists() {
+ return reload(SubnetworkOption.fields()) != null;
+ }
+
+ /**
+ * Fetches current subnetwork' latest information. Returns {@code null} if the subnetwork does not
+ * exist.
+ *
+ * @param options subnetwork options
+ * @return an {@code Subnetwork} object with latest information or {@code null} if not found
+ * @throws ComputeException upon failure
+ */
+ public Subnetwork reload(SubnetworkOption... options) {
+ return compute.get(subnetworkId(), options);
+ }
+
+ /**
+ * Deletes this subnetwork. If this subnetwork was auto-generated deletion will fail.
+ *
+ * @return an operation object if delete request was successfully sent, {@code null} if the
+ * subnetwork was not found
+ * @throws ComputeException upon failure
+ */
+ public Operation delete(OperationOption... options) {
+ return compute.delete(subnetworkId(), options);
+ }
+
+ /**
+ * Returns the subnetwork's {@code Compute} object used to issue requests.
+ */
+ public Compute compute() {
+ return compute;
+ }
+
+ @Override
+ public Builder toBuilder() {
+ return new Builder(this);
+ }
+
+ @Override
+ public final boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj == null || !obj.getClass().equals(Subnetwork.class)) {
+ return false;
+ }
+ Subnetwork other = (Subnetwork) obj;
+ return Objects.equals(toPb(), other.toPb()) && Objects.equals(options, other.options);
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(super.hashCode(), options);
+ }
+
+ private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException {
+ input.defaultReadObject();
+ this.compute = options.service();
+ }
+
+ static Subnetwork fromPb(Compute compute,
+ com.google.api.services.compute.model.Subnetwork subnetworkPb) {
+ return new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(subnetworkPb));
+ }
+}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SubnetworkInfo.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SubnetworkInfo.java
index 5be0d875d738..d6988ee7eea8 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SubnetworkInfo.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SubnetworkInfo.java
@@ -289,7 +289,8 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
- return obj != null
+ return obj == this
+ || obj != null
&& obj.getClass().equals(SubnetworkInfo.class)
&& Objects.equals(toPb(), ((SubnetworkInfo) obj).toPb());
}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/spi/ComputeRpc.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/spi/ComputeRpc.java
index b24384af37f2..f3e51266aa50 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/spi/ComputeRpc.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/spi/ComputeRpc.java
@@ -23,9 +23,11 @@
import com.google.api.services.compute.model.Image;
import com.google.api.services.compute.model.License;
import com.google.api.services.compute.model.MachineType;
+import com.google.api.services.compute.model.Network;
import com.google.api.services.compute.model.Operation;
import com.google.api.services.compute.model.Region;
import com.google.api.services.compute.model.Snapshot;
+import com.google.api.services.compute.model.Subnetwork;
import com.google.api.services.compute.model.Zone;
import com.google.gcloud.compute.ComputeException;
@@ -424,4 +426,74 @@ Operation deprecateImage(String project, String image, DeprecationStatus depreca
* @throws ComputeException upon failure or if the new disk size is smaller than the previous one
*/
Operation resizeDisk(String zone, String disk, long sizeGb, Map