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 options); + + /* + * Creates a new subnetwork. + * + * @return a region operation for subnetwork's creation + * @throws ComputeException upon failure + */ + Operation createSubnetwork(String region, Subnetwork subnetwork, Map options); + + /** + * Returns the requested subnetwork or {@code null} if not found. + * + * @throws ComputeException upon failure + */ + Subnetwork getSubnetwork(String region, String subnetwork, Map options); + + /** + * Lists subnetworks for the provided region. + * + * @throws ComputeException upon failure + */ + Tuple> listSubnetworks(String region, Map options); + + /** + * Lists subnetworks. + * + * @throws ComputeException upon failure + */ + Tuple> listSubnetworks(Map 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 deleteSubnetwork(String region, String subnetwork, Map options); + + /** + * Creates a new network. + * + * @return a global operation for network's creation + * @throws ComputeException upon failure + */ + Operation createNetwork(Network network, Map options); + + /** + * Returns the requested network or {@code null} if not found. + * + * @throws ComputeException upon failure + */ + Network getNetwork(String network, Map options); + + /** + * Lists networks. + * + * @throws ComputeException upon failure + */ + Tuple> listNetworks(Map 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, Map options); } diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/spi/DefaultComputeRpc.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/spi/DefaultComputeRpc.java index 708e5fa2ceee..9db50af5db4c 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/spi/DefaultComputeRpc.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/spi/DefaultComputeRpc.java @@ -47,12 +47,18 @@ import com.google.api.services.compute.model.MachineTypeAggregatedList; import com.google.api.services.compute.model.MachineTypeList; import com.google.api.services.compute.model.MachineTypesScopedList; +import com.google.api.services.compute.model.Network; +import com.google.api.services.compute.model.NetworkList; import com.google.api.services.compute.model.Operation; import com.google.api.services.compute.model.OperationList; import com.google.api.services.compute.model.Region; import com.google.api.services.compute.model.RegionList; import com.google.api.services.compute.model.Snapshot; import com.google.api.services.compute.model.SnapshotList; +import com.google.api.services.compute.model.Subnetwork; +import com.google.api.services.compute.model.SubnetworkAggregatedList; +import com.google.api.services.compute.model.SubnetworkList; +import com.google.api.services.compute.model.SubnetworksScopedList; import com.google.api.services.compute.model.Zone; import com.google.api.services.compute.model.ZoneList; import com.google.common.collect.ImmutableList; @@ -730,6 +736,139 @@ public Operation resizeDisk(String zone, String disk, long sizeGb, Map options) { + try { + return compute.subnetworks() + .insert(this.options.projectId(), region, subnetwork) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Subnetwork getSubnetwork(String region, String subnetwork, Map options) { + try { + return compute.subnetworks() + .get(this.options.projectId(), region, subnetwork) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Tuple> listSubnetworks(String region, + Map options) { + try { + SubnetworkList subnetworkList = compute.subnetworks() + .list(this.options.projectId(), region) + .setFilter(FILTER.getString(options)) + .setMaxResults(MAX_RESULTS.getLong(options)) + .setPageToken(PAGE_TOKEN.getString(options)) + .setFields(FIELDS.getString(options)) + .execute(); + Iterable subnetworks = subnetworkList.getItems(); + return Tuple.of(subnetworkList.getNextPageToken(), subnetworks); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Tuple> listSubnetworks(Map options) { + try { + SubnetworkAggregatedList aggregatedList = compute.subnetworks() + .aggregatedList(this.options.projectId()) + .setFilter(FILTER.getString(options)) + .setMaxResults(MAX_RESULTS.getLong(options)) + .setPageToken(PAGE_TOKEN.getString(options)) + // todo(mziccard): uncomment or remove once #711 is closed + // .setFields(FIELDS.getString(options)) + .execute(); + ImmutableList.Builder builder = ImmutableList.builder(); + Map scopedList = aggregatedList.getItems(); + if (scopedList != null) { + for (SubnetworksScopedList subnetworksScopedList : scopedList.values()) { + if (subnetworksScopedList.getSubnetworks() != null) { + builder.addAll(subnetworksScopedList.getSubnetworks()); + } + } + } + return Tuple.>of(aggregatedList.getNextPageToken(), + builder.build()); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Operation deleteSubnetwork(String region, String subnetwork, Map options) { + try { + return compute.subnetworks() + .delete(this.options.projectId(), region, subnetwork) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Operation createNetwork(Network network, Map options) { + try { + return compute.networks() + .insert(this.options.projectId(), network) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Network getNetwork(String network, Map options) { + try { + return compute.networks() + .get(this.options.projectId(), network) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Tuple> listNetworks(Map options) { + try { + NetworkList networkList = compute.networks() + .list(this.options.projectId()) + .setFilter(FILTER.getString(options)) + .setMaxResults(MAX_RESULTS.getLong(options)) + .setPageToken(PAGE_TOKEN.getString(options)) + .setFields(FIELDS.getString(options)) + .execute(); + Iterable networks = networkList.getItems(); + return Tuple.of(networkList.getNextPageToken(), networks); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Operation deleteNetwork(String network, Map options) { + try { + return compute.networks() + .delete(this.options.projectId(), network) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + /** * This method returns {@code null} if the error code of {@code exception} was 404, re-throws the * exception otherwise. diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ComputeImplTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ComputeImplTest.java index edd8b2bd0cef..85ddd0e3595b 100644 --- a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ComputeImplTest.java +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ComputeImplTest.java @@ -56,6 +56,10 @@ import com.google.gcloud.compute.Compute.MachineTypeFilter; import com.google.gcloud.compute.Compute.MachineTypeListOption; import com.google.gcloud.compute.Compute.MachineTypeOption; +import com.google.gcloud.compute.Compute.NetworkField; +import com.google.gcloud.compute.Compute.NetworkFilter; +import com.google.gcloud.compute.Compute.NetworkListOption; +import com.google.gcloud.compute.Compute.NetworkOption; import com.google.gcloud.compute.Compute.OperationFilter; import com.google.gcloud.compute.Compute.OperationListOption; import com.google.gcloud.compute.Compute.OperationOption; @@ -65,6 +69,11 @@ import com.google.gcloud.compute.Compute.SnapshotFilter; import com.google.gcloud.compute.Compute.SnapshotListOption; import com.google.gcloud.compute.Compute.SnapshotOption; +import com.google.gcloud.compute.Compute.SubnetworkAggregatedListOption; +import com.google.gcloud.compute.Compute.SubnetworkField; +import com.google.gcloud.compute.Compute.SubnetworkFilter; +import com.google.gcloud.compute.Compute.SubnetworkListOption; +import com.google.gcloud.compute.Compute.SubnetworkOption; import com.google.gcloud.compute.Compute.ZoneFilter; import com.google.gcloud.compute.Compute.ZoneListOption; import com.google.gcloud.compute.Compute.ZoneOption; @@ -198,6 +207,12 @@ public class ComputeImplTest { DeprecationStatus.builder(DeprecationStatus.Status.DEPRECATED, IMAGE_ID).build(); private static final DiskInfo DISK = DiskInfo.of(DISK_ID, StandardDiskConfiguration.of(DISK_TYPE_ID)); + private static final NetworkId NETWORK_ID = NetworkId.of("project", "network"); + private static final SubnetworkId SUBNETWORK_ID = SubnetworkId.of("project", "region", "network"); + private static final SubnetworkInfo SUBNETWORK = + SubnetworkInfo.of(SUBNETWORK_ID, NETWORK_ID, "192.168.0.0/16"); + private static final NetworkInfo NETWORK = + NetworkInfo.of(NETWORK_ID, StandardNetworkConfiguration.of("192.168.0.0/16")); // Empty ComputeRpc options private static final Map EMPTY_RPC_OPTIONS = ImmutableMap.of(); @@ -391,6 +406,50 @@ public class ComputeImplTest { private static final DiskAggregatedListOption DISK_AGGREGATED_LIST_FILTER = DiskAggregatedListOption.filter(DISK_FILTER); + // Subnetwork options + private static final SubnetworkOption SUBNETWORK_OPTION_FIELDS = + SubnetworkOption.fields(SubnetworkField.ID, SubnetworkField.DESCRIPTION); + + // Subnetwork list options + private static final SubnetworkFilter SUBNETWORK_FILTER = + SubnetworkFilter.equals(SubnetworkField.IP_CIDR_RANGE, "192.168.0.0/16"); + private static final SubnetworkListOption SUBNETWORK_LIST_PAGE_TOKEN = + SubnetworkListOption.pageToken("cursor"); + private static final SubnetworkListOption SUBNETWORK_LIST_PAGE_SIZE = + SubnetworkListOption.pageSize(42L); + private static final SubnetworkListOption SUBNETWORK_LIST_FILTER = + SubnetworkListOption.filter(SUBNETWORK_FILTER); + private static final Map SUBNETWORK_LIST_OPTIONS = ImmutableMap.of( + PAGE_TOKEN, "cursor", + MAX_RESULTS, 42L, + FILTER, "ipCidrRange eq 192.168.0.0/16"); + + // Subnetwork aggregated list options + private static final SubnetworkAggregatedListOption SUBNETWORK_AGGREGATED_LIST_PAGE_TOKEN = + SubnetworkAggregatedListOption.pageToken("cursor"); + private static final SubnetworkAggregatedListOption SUBNETWORK_AGGREGATED_LIST_PAGE_SIZE = + SubnetworkAggregatedListOption.pageSize(42L); + private static final SubnetworkAggregatedListOption SUBNETWORK_AGGREGATED_LIST_FILTER = + SubnetworkAggregatedListOption.filter(SUBNETWORK_FILTER); + + // Network options + private static final NetworkOption NETWORK_OPTION_FIELDS = + NetworkOption.fields(NetworkField.ID, NetworkField.DESCRIPTION); + + // Network list options + private static final NetworkFilter NETWORK_FILTER = + NetworkFilter.equals(NetworkField.IPV4_RANGE, "192.168.0.0/16"); + private static final NetworkListOption NETWORK_LIST_PAGE_TOKEN = + NetworkListOption.pageToken("cursor"); + private static final NetworkListOption NETWORK_LIST_PAGE_SIZE = + NetworkListOption.pageSize(42L); + private static final NetworkListOption NETWORK_LIST_FILTER = + NetworkListOption.filter(NETWORK_FILTER); + private static final Map NETWORK_LIST_OPTIONS = ImmutableMap.of( + PAGE_TOKEN, "cursor", + MAX_RESULTS, 42L, + FILTER, "IPv4Range eq 192.168.0.0/16"); + private static final Function OPERATION_TO_PB_FUNCTION = new Function() { @@ -2680,6 +2739,433 @@ public void testResizeDisk_Null() { assertNull(compute.resize(DISK_ID, 42L)); } + @Test + public void testGetSubnetwork() { + EasyMock.expect(computeRpcMock.getSubnetwork(SUBNETWORK_ID.region(), SUBNETWORK_ID.subnetwork(), + EMPTY_RPC_OPTIONS)).andReturn(SUBNETWORK.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Subnetwork subnetwork = compute.get(SUBNETWORK_ID); + assertEquals(new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK)), subnetwork); + } + + @Test + public void testGetSubnetwork_Null() { + EasyMock.expect(computeRpcMock.getSubnetwork(SUBNETWORK_ID.region(), SUBNETWORK_ID.subnetwork(), + EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.get(SUBNETWORK_ID)); + } + + @Test + public void testGetSubnetworkWithSelectedFields() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.getSubnetwork(eq(SUBNETWORK_ID.region()), + eq(SUBNETWORK_ID.subnetwork()), capture(capturedOptions))).andReturn(SUBNETWORK.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Subnetwork subnetwork = compute.get(SUBNETWORK_ID, SUBNETWORK_OPTION_FIELDS); + String selector = (String) capturedOptions.getValue().get(SUBNETWORK_OPTION_FIELDS.rpcOption()); + assertTrue(selector.contains("selfLink")); + assertTrue(selector.contains("id")); + assertTrue(selector.contains("description")); + assertEquals(23, selector.length()); + assertEquals(new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK)), subnetwork); + } + + @Test + public void testDeleteSubnetwork_Operation() { + EasyMock.expect(computeRpcMock.deleteSubnetwork(SUBNETWORK_ID.region(), + SUBNETWORK_ID.subnetwork(), EMPTY_RPC_OPTIONS)).andReturn(regionOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(regionOperation, compute.delete(SUBNETWORK_ID)); + } + + @Test + public void testDeleteSubnetworkWithSelectedFields_Operation() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.deleteSubnetwork(eq(SUBNETWORK_ID.region()), + eq(SUBNETWORK_ID.subnetwork()), capture(capturedOptions))) + .andReturn(regionOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.delete(SUBNETWORK_ID, OPERATION_OPTION_FIELDS); + String selector = (String) capturedOptions.getValue().get(OPERATION_OPTION_FIELDS.rpcOption()); + assertTrue(selector.contains("selfLink")); + assertTrue(selector.contains("id")); + assertTrue(selector.contains("description")); + assertEquals(23, selector.length()); + assertEquals(regionOperation, operation); + } + + @Test + public void testDeleteSubnetwork_Null() { + EasyMock.expect(computeRpcMock.deleteSubnetwork(SUBNETWORK_ID.region(), + SUBNETWORK_ID.subnetwork(), EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.delete(SUBNETWORK_ID)); + } + + @Test + public void testListSubnetworks() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList subnetworkList = ImmutableList.of( + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK)), + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(subnetworkList, SubnetworkInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listSubnetworks(SUBNETWORK_ID.region(), EMPTY_RPC_OPTIONS)) + .andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listSubnetworks(SUBNETWORK_ID.region()); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(subnetworkList.toArray(), Iterables.toArray(page.values(), Subnetwork.class)); + } + + @Test + public void testListSubnetworksNextPage() { + String cursor = "cursor"; + String nextCursor = "nextCursor"; + compute = options.service(); + ImmutableList subnetworkList = ImmutableList.of( + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK)), + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK))); + ImmutableList nextSubnetworkList = ImmutableList.of( + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(subnetworkList, SubnetworkInfo.TO_PB_FUNCTION)); + Tuple> nextResult = + Tuple.of(nextCursor, + Iterables.transform(nextSubnetworkList, SubnetworkInfo.TO_PB_FUNCTION)); + Map nextOptions = ImmutableMap.of(PAGE_TOKEN, cursor); + EasyMock.expect(computeRpcMock.listSubnetworks(SUBNETWORK_ID.region(), EMPTY_RPC_OPTIONS)) + .andReturn(result); + EasyMock.expect(computeRpcMock.listSubnetworks(SUBNETWORK_ID.region(), nextOptions)) + .andReturn(nextResult); + EasyMock.replay(computeRpcMock); + Page page = compute.listSubnetworks(SUBNETWORK_ID.region()); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(subnetworkList.toArray(), Iterables.toArray(page.values(), Subnetwork.class)); + page = page.nextPage(); + assertEquals(nextCursor, page.nextPageCursor()); + assertArrayEquals(nextSubnetworkList.toArray(), + Iterables.toArray(page.values(), Subnetwork.class)); + } + + @Test + public void testListEmptySubnetworks() { + compute = options.service(); + ImmutableList subnetworks = + ImmutableList.of(); + Tuple> result = + Tuple.>of(null, + subnetworks); + EasyMock.expect(computeRpcMock.listSubnetworks(SUBNETWORK_ID.region(), EMPTY_RPC_OPTIONS)) + .andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listSubnetworks(SUBNETWORK_ID.region()); + assertNull(page.nextPageCursor()); + assertArrayEquals(subnetworks.toArray(), Iterables.toArray(page.values(), Subnetwork.class)); + } + + @Test + public void testListSubnetworksWithOptions() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList subnetworkList = ImmutableList.of( + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK)), + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(subnetworkList, SubnetworkInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listSubnetworks(SUBNETWORK_ID.region(), SUBNETWORK_LIST_OPTIONS)) + .andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listSubnetworks(SUBNETWORK_ID.region(), + SUBNETWORK_LIST_PAGE_SIZE, SUBNETWORK_LIST_PAGE_TOKEN, SUBNETWORK_LIST_FILTER); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(subnetworkList.toArray(), Iterables.toArray(page.values(), Subnetwork.class)); + } + + @Test + public void testAggregatedListSubnetworks() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList subnetworkList = ImmutableList.of( + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK)), + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(subnetworkList, SubnetworkInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listSubnetworks(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listSubnetworks(); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(subnetworkList.toArray(), Iterables.toArray(page.values(), Subnetwork.class)); + } + + @Test + public void testAggregatedListSubnetworksNextPage() { + String cursor = "cursor"; + String nextCursor = "nextCursor"; + compute = options.service(); + ImmutableList subnetworkList = ImmutableList.of( + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK)), + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK))); + ImmutableList nextSubnetworkList = ImmutableList.of( + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(subnetworkList, SubnetworkInfo.TO_PB_FUNCTION)); + Tuple> nextResult = + Tuple.of(nextCursor, + Iterables.transform(nextSubnetworkList, SubnetworkInfo.TO_PB_FUNCTION)); + Map nextOptions = ImmutableMap.of(PAGE_TOKEN, cursor); + EasyMock.expect(computeRpcMock.listSubnetworks(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.expect(computeRpcMock.listSubnetworks(nextOptions)).andReturn(nextResult); + EasyMock.replay(computeRpcMock); + Page page = compute.listSubnetworks(); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(subnetworkList.toArray(), Iterables.toArray(page.values(), Subnetwork.class)); + page = page.nextPage(); + assertEquals(nextCursor, page.nextPageCursor()); + assertArrayEquals(nextSubnetworkList.toArray(), + Iterables.toArray(page.values(), Subnetwork.class)); + } + + @Test + public void testAggregatedListEmptySubnetworks() { + compute = options.service(); + ImmutableList subnetworks = + ImmutableList.of(); + Tuple> result = + Tuple.>of(null, + subnetworks); + EasyMock.expect(computeRpcMock.listSubnetworks(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listSubnetworks(); + assertNull(page.nextPageCursor()); + assertArrayEquals(subnetworks.toArray(), Iterables.toArray(page.values(), Subnetwork.class)); + } + + @Test + public void testAggregatedListSubnetworksWithOptions() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList subnetworkList = ImmutableList.of( + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK)), + new Subnetwork(compute, new SubnetworkInfo.BuilderImpl(SUBNETWORK))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(subnetworkList, SubnetworkInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listSubnetworks(SUBNETWORK_LIST_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listSubnetworks(SUBNETWORK_AGGREGATED_LIST_PAGE_SIZE, + SUBNETWORK_AGGREGATED_LIST_PAGE_TOKEN, SUBNETWORK_AGGREGATED_LIST_FILTER); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(subnetworkList.toArray(), Iterables.toArray(page.values(), Subnetwork.class)); + } + + @Test + public void testCreateSubnetwork() { + EasyMock.expect(computeRpcMock.createSubnetwork(SUBNETWORK_ID.region(), SUBNETWORK.toPb(), + EMPTY_RPC_OPTIONS)).andReturn(regionOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + SubnetworkId subnetworkId = SubnetworkId.of("region", "network"); + NetworkId networkId = NetworkId.of("network"); + SubnetworkInfo subnetwork = SubnetworkInfo.of(subnetworkId, networkId, "192.168.0.0/16"); + Operation operation = compute.create(subnetwork); + assertEquals(regionOperation, operation); + } + + @Test + public void testCreateSubnetworkWithOptions() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.createSubnetwork(eq(SUBNETWORK_ID.region()), + eq(SUBNETWORK.toPb()), capture(capturedOptions))).andReturn(regionOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.create(SUBNETWORK, OPERATION_OPTION_FIELDS); + String selector = (String) capturedOptions.getValue().get(OPERATION_OPTION_FIELDS.rpcOption()); + assertTrue(selector.contains("selfLink")); + assertTrue(selector.contains("id")); + assertTrue(selector.contains("description")); + assertEquals(23, selector.length()); + assertEquals(regionOperation, operation); + } + + @Test + public void testGetNetwork() { + EasyMock.expect(computeRpcMock.getNetwork(NETWORK_ID.network(), EMPTY_RPC_OPTIONS)) + .andReturn(NETWORK.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Network network = compute.getNetwork(NETWORK_ID.network()); + assertEquals(new Network(compute, new NetworkInfo.BuilderImpl(NETWORK)), network); + } + + @Test + public void testGetNetwork_Null() { + EasyMock.expect(computeRpcMock.getNetwork(NETWORK_ID.network(), EMPTY_RPC_OPTIONS)) + .andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.getNetwork(NETWORK_ID.network())); + } + + @Test + public void testGetNetworkWithSelectedFields() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.getNetwork(eq(NETWORK_ID.network()), capture(capturedOptions))) + .andReturn(NETWORK.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Network network = compute.getNetwork(NETWORK_ID.network(), NETWORK_OPTION_FIELDS); + String selector = (String) capturedOptions.getValue().get(NETWORK_OPTION_FIELDS.rpcOption()); + assertTrue(selector.contains("selfLink")); + assertTrue(selector.contains("id")); + assertTrue(selector.contains("description")); + assertTrue(selector.contains("IPv4Range")); + assertTrue(selector.contains("autoCreateSubnetworks")); + assertEquals(55, selector.length()); + assertEquals(new Network(compute, new NetworkInfo.BuilderImpl(NETWORK)), network); + } + + @Test + public void testDeleteNetwork_Operation() { + EasyMock.expect(computeRpcMock.deleteNetwork(NETWORK_ID.network(), EMPTY_RPC_OPTIONS)) + .andReturn(globalOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(globalOperation, compute.deleteNetwork(NETWORK_ID)); + } + + @Test + public void testDeleteNetworkWithSelectedFields_Operation() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.deleteNetwork(eq(NETWORK_ID.network()), + capture(capturedOptions))).andReturn(globalOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.deleteNetwork(NETWORK_ID, OPERATION_OPTION_FIELDS); + String selector = (String) capturedOptions.getValue().get(OPERATION_OPTION_FIELDS.rpcOption()); + assertTrue(selector.contains("selfLink")); + assertTrue(selector.contains("id")); + assertTrue(selector.contains("description")); + assertEquals(23, selector.length()); + assertEquals(globalOperation, operation); + } + + @Test + public void testDeleteNetwork_Null() { + EasyMock.expect(computeRpcMock.deleteNetwork(NETWORK_ID.network(), EMPTY_RPC_OPTIONS)) + .andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.deleteNetwork(NETWORK_ID)); + } + + @Test + public void testListNetworks() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList networkList = ImmutableList.of( + new Network(compute, new NetworkInfo.BuilderImpl(NETWORK)), + new Network(compute, new NetworkInfo.BuilderImpl(NETWORK))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(networkList, NetworkInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listNetworks(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listNetworks(); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(networkList.toArray(), Iterables.toArray(page.values(), Network.class)); + } + + @Test + public void testListNetworksNextPage() { + String cursor = "cursor"; + String nextCursor = "nextCursor"; + compute = options.service(); + ImmutableList networkList = ImmutableList.of( + new Network(compute, new NetworkInfo.BuilderImpl(NETWORK)), + new Network(compute, new NetworkInfo.BuilderImpl(NETWORK))); + ImmutableList nextNetworkList = ImmutableList.of( + new Network(compute, new NetworkInfo.BuilderImpl(NETWORK))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(networkList, NetworkInfo.TO_PB_FUNCTION)); + Tuple> nextResult = + Tuple.of(nextCursor, Iterables.transform(nextNetworkList, NetworkInfo.TO_PB_FUNCTION)); + Map nextOptions = ImmutableMap.of(PAGE_TOKEN, cursor); + EasyMock.expect(computeRpcMock.listNetworks(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.expect(computeRpcMock.listNetworks(nextOptions)).andReturn(nextResult); + EasyMock.replay(computeRpcMock); + Page page = compute.listNetworks(); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(networkList.toArray(), Iterables.toArray(page.values(), Network.class)); + page = page.nextPage(); + assertEquals(nextCursor, page.nextPageCursor()); + assertArrayEquals(nextNetworkList.toArray(), Iterables.toArray(page.values(), Network.class)); + } + + @Test + public void testListEmptyNetworks() { + compute = options.service(); + ImmutableList networks = ImmutableList.of(); + Tuple> result = + Tuple.>of(null, networks); + EasyMock.expect(computeRpcMock.listNetworks(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listNetworks(); + assertNull(page.nextPageCursor()); + assertArrayEquals(networks.toArray(), Iterables.toArray(page.values(), Network.class)); + } + + @Test + public void testListNetworksWithOptions() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList networkList = ImmutableList.of( + new Network(compute, new NetworkInfo.BuilderImpl(NETWORK)), + new Network(compute, new NetworkInfo.BuilderImpl(NETWORK))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(networkList, NetworkInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listNetworks(NETWORK_LIST_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listNetworks(NETWORK_LIST_PAGE_SIZE, NETWORK_LIST_PAGE_TOKEN, + NETWORK_LIST_FILTER); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(networkList.toArray(), Iterables.toArray(page.values(), Network.class)); + } + + @Test + public void testCreateNetwork() { + EasyMock.expect(computeRpcMock.createNetwork(NETWORK.toPb(), EMPTY_RPC_OPTIONS)) + .andReturn(globalOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + NetworkInfo network = + NetworkInfo.of(NetworkId.of("network"), StandardNetworkConfiguration.of("192.168.0.0/16")); + Operation operation = compute.create(network); + assertEquals(globalOperation, operation); + } + + @Test + public void testCreateNetworkWithOptions() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.createNetwork(eq(NETWORK.toPb()), capture(capturedOptions))) + .andReturn(globalOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.create(NETWORK, OPERATION_OPTION_FIELDS); + String selector = (String) capturedOptions.getValue().get(OPERATION_OPTION_FIELDS.rpcOption()); + assertTrue(selector.contains("selfLink")); + assertTrue(selector.contains("id")); + assertTrue(selector.contains("description")); + assertEquals(23, selector.length()); + assertEquals(globalOperation, operation); + } + @Test public void testRetryableException() { EasyMock.expect( diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/NetworkTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/NetworkTest.java new file mode 100644 index 000000000000..3d303702ecc4 --- /dev/null +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/NetworkTest.java @@ -0,0 +1,259 @@ +/* + * 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 org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.createStrictMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import com.google.common.collect.ImmutableList; + +import org.junit.Test; + +import java.util.List; + +public class NetworkTest { + + private static final String ID = "42"; + private static final Long CREATION_TIMESTAMP = 1453293540000L; + private static final String DESCRIPTION = "description"; + private static final SubnetworkId SUBNETWORK1 = SubnetworkId.of("project", "region1", "network1"); + private static final SubnetworkId SUBNETWORK2 = SubnetworkId.of("project", "region2", "network2"); + private static final List SUBNETWORKS = ImmutableList.of(SUBNETWORK1, SUBNETWORK2); + private static final String GATEWAY_ADDRESS = "192.168.1.1"; + private static final NetworkId NETWORK_ID = NetworkId.of("project", "network"); + private static final String IP_RANGE = "192.168.0.0/16"; + private static final Boolean AUTO_CREATE_SUBNETWORKS = true; + private static final StandardNetworkConfiguration NETWORK_CONFIGURATION = + new StandardNetworkConfiguration(IP_RANGE, GATEWAY_ADDRESS); + private static final SubnetNetworkConfiguration SUBNET_NETWORK_CONFIGURATION = + new SubnetNetworkConfiguration(AUTO_CREATE_SUBNETWORKS, SUBNETWORKS); + + private final Compute serviceMockReturnsOptions = createStrictMock(Compute.class); + private final ComputeOptions mockOptions = createMock(ComputeOptions.class); + private Compute compute; + private Network network; + private Network standardNetwork; + private Network subnetNetwork; + + private void initializeExpectedNetwork(int optionsCalls) { + expect(serviceMockReturnsOptions.options()).andReturn(mockOptions).times(optionsCalls); + replay(serviceMockReturnsOptions); + standardNetwork = + new Network.Builder(serviceMockReturnsOptions, NETWORK_ID, NETWORK_CONFIGURATION) + .id(ID) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .build(); + subnetNetwork = + new Network.Builder(serviceMockReturnsOptions, NETWORK_ID, SUBNET_NETWORK_CONFIGURATION) + .id(ID) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .build(); + compute = createStrictMock(Compute.class); + } + + private void initializeNetwork() { + network = new Network.Builder(compute, NETWORK_ID, NETWORK_CONFIGURATION) + .id(ID) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .build(); + } + + @Test + public void testToBuilder() { + initializeExpectedNetwork(9); + compareNetwork(standardNetwork, standardNetwork.toBuilder().build()); + Network newNetwork = standardNetwork.toBuilder().description("newDescription").build(); + assertEquals("newDescription", newNetwork.description()); + newNetwork = newNetwork.toBuilder().description("description").build(); + compareNetwork(standardNetwork, newNetwork); + } + + @Test + public void testToBuilderIncomplete() { + initializeExpectedNetwork(6); + NetworkInfo networkInfo = NetworkInfo.of(NETWORK_ID, NETWORK_CONFIGURATION); + Network network = + new Network(serviceMockReturnsOptions, new NetworkInfo.BuilderImpl(networkInfo)); + compareNetwork(network, network.toBuilder().build()); + } + + @Test + public void testBuilder() { + initializeExpectedNetwork(2); + assertEquals(ID, standardNetwork.id()); + assertEquals(NETWORK_ID, standardNetwork.networkId()); + assertEquals(CREATION_TIMESTAMP, standardNetwork.creationTimestamp()); + assertEquals(DESCRIPTION, standardNetwork.description()); + assertEquals(NETWORK_CONFIGURATION, standardNetwork.configuration()); + assertSame(serviceMockReturnsOptions, standardNetwork.compute()); + assertEquals(ID, subnetNetwork.id()); + assertEquals(NETWORK_ID, subnetNetwork.networkId()); + assertEquals(CREATION_TIMESTAMP, subnetNetwork.creationTimestamp()); + assertEquals(DESCRIPTION, subnetNetwork.description()); + assertEquals(SUBNET_NETWORK_CONFIGURATION, subnetNetwork.configuration()); + assertSame(serviceMockReturnsOptions, subnetNetwork.compute()); + } + + @Test + public void testToAndFromPb() { + initializeExpectedNetwork(12); + compareNetwork(standardNetwork, + Network.fromPb(serviceMockReturnsOptions, standardNetwork.toPb())); + compareNetwork(subnetNetwork, + Network.fromPb(serviceMockReturnsOptions, subnetNetwork.toPb())); + Network network = + new Network.Builder(serviceMockReturnsOptions, NETWORK_ID, NETWORK_CONFIGURATION).build(); + compareNetwork(network, Network.fromPb(serviceMockReturnsOptions, network.toPb())); + } + + @Test + public void testDeleteOperation() { + initializeExpectedNetwork(3); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(GlobalOperationId.of("project", "op")) + .build(); + expect(compute.deleteNetwork(NETWORK_ID.network())).andReturn(operation); + replay(compute); + initializeNetwork(); + assertSame(operation, network.delete()); + } + + @Test + public void testDeleteNull() { + initializeExpectedNetwork(2); + expect(compute.options()).andReturn(mockOptions); + expect(compute.deleteNetwork(NETWORK_ID.network())).andReturn(null); + replay(compute); + initializeNetwork(); + assertNull(network.delete()); + } + + @Test + public void testExists_True() throws Exception { + initializeExpectedNetwork(2); + Compute.NetworkOption[] expectedOptions = {Compute.NetworkOption.fields()}; + expect(compute.options()).andReturn(mockOptions); + expect(compute.getNetwork(NETWORK_ID.network(), expectedOptions)) + .andReturn(standardNetwork); + replay(compute); + initializeNetwork(); + assertTrue(network.exists()); + verify(compute); + } + + @Test + public void testExists_False() throws Exception { + initializeExpectedNetwork(2); + Compute.NetworkOption[] expectedOptions = {Compute.NetworkOption.fields()}; + expect(compute.options()).andReturn(mockOptions); + expect(compute.getNetwork(NETWORK_ID.network(), expectedOptions)).andReturn(null); + replay(compute); + initializeNetwork(); + assertFalse(network.exists()); + verify(compute); + } + + @Test + public void testReload() throws Exception { + initializeExpectedNetwork(4); + expect(compute.options()).andReturn(mockOptions); + expect(compute.getNetwork(NETWORK_ID.network())).andReturn(standardNetwork); + replay(compute); + initializeNetwork(); + Network updatedNetwork = network.reload(); + compareNetwork(standardNetwork, updatedNetwork); + verify(compute); + } + + @Test + public void testReloadNull() throws Exception { + initializeExpectedNetwork(2); + expect(compute.options()).andReturn(mockOptions); + expect(compute.getNetwork(NETWORK_ID.network())).andReturn(null); + replay(compute); + initializeNetwork(); + assertNull(network.reload()); + verify(compute); + } + + @Test + public void testReloadWithOptions() throws Exception { + initializeExpectedNetwork(4); + expect(compute.options()).andReturn(mockOptions); + expect(compute.getNetwork(NETWORK_ID.network(), Compute.NetworkOption.fields())) + .andReturn(standardNetwork); + replay(compute); + initializeNetwork(); + Network updatedNetwork = network.reload(Compute.NetworkOption.fields()); + compareNetwork(standardNetwork, updatedNetwork); + verify(compute); + } + + @Test + public void testCreateSubnetwork() throws Exception { + initializeExpectedNetwork(3); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(RegionOperationId.of(SUBNETWORK1.regionId(), "op")) + .build(); + expect(compute.options()).andReturn(mockOptions); + expect(compute.create(SubnetworkInfo.of(SUBNETWORK1, NETWORK_ID, IP_RANGE))) + .andReturn(operation); + replay(compute); + initializeNetwork(); + assertSame(operation, network.createSubnetwork(SUBNETWORK1, IP_RANGE)); + verify(compute); + } + + @Test + public void testCreateSubnetworkWithOptions() throws Exception { + initializeExpectedNetwork(3); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(RegionOperationId.of(SUBNETWORK1.regionId(), "op")) + .build(); + expect(compute.options()).andReturn(mockOptions); + expect(compute.create(SubnetworkInfo.of(SUBNETWORK1, NETWORK_ID, IP_RANGE), + Compute.OperationOption.fields())).andReturn(operation); + replay(compute); + initializeNetwork(); + assertSame(operation, + network.createSubnetwork(SUBNETWORK1, IP_RANGE, Compute.OperationOption.fields())); + verify(compute); + } + + public void compareNetwork(Network expected, Network value) { + assertEquals(expected, value); + assertEquals(expected.compute().options(), value.compute().options()); + assertEquals(expected.id(), value.id()); + assertEquals(expected.networkId(), value.networkId()); + assertEquals(expected.creationTimestamp(), value.creationTimestamp()); + assertEquals(expected.description(), value.description()); + assertEquals(expected.configuration(), value.configuration()); + assertEquals(expected.hashCode(), value.hashCode()); + } +} diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SerializationTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SerializationTest.java index 5f06d252af34..2e5dbdca6ceb 100644 --- a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SerializationTest.java +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SerializationTest.java @@ -161,6 +161,16 @@ public class SerializationTest { private static final NetworkId NETWORK_ID = NetworkId.of("project", "network"); private static final SubnetworkInfo SUBNETWORK_INFO = SubnetworkInfo.of(SUBNETWORK_ID, NETWORK_ID, "192.168.0.0/16"); + private static final Subnetwork SUBNETWORK = + new Subnetwork.Builder(COMPUTE, SUBNETWORK_ID, NETWORK_ID, "192.168.0.0/16").build(); + private static final StandardNetworkConfiguration STANDARD_NETWORK_CONFIGURATION = + StandardNetworkConfiguration.of("192.168.0.0/16"); + private static final SubnetNetworkConfiguration SUBNET_NETWORK_CONFIGURATION = + SubnetNetworkConfiguration.of(false); + private static final NetworkInfo NETWORK_INFO = + NetworkInfo.of(NETWORK_ID, STANDARD_NETWORK_CONFIGURATION); + private static final Network NETWORK = + new Network.Builder(COMPUTE, NETWORK_ID, STANDARD_NETWORK_CONFIGURATION).build(); private static final Compute.DiskTypeOption DISK_TYPE_OPTION = Compute.DiskTypeOption.fields(); private static final Compute.DiskTypeFilter DISK_TYPE_FILTER = @@ -217,6 +227,20 @@ public class SerializationTest { Compute.DiskListOption.filter(DISK_FILTER); private static final Compute.DiskAggregatedListOption DISK_AGGREGATED_LIST_OPTION = Compute.DiskAggregatedListOption.filter(DISK_FILTER); + private static final Compute.SubnetworkOption SUBNETWORK_OPTION = + Compute.SubnetworkOption.fields(); + private static final Compute.SubnetworkFilter SUBNETWORK_FILTER = + Compute.SubnetworkFilter.equals(Compute.SubnetworkField.SELF_LINK, "selfLink"); + private static final Compute.SubnetworkListOption SUBNETWORK_LIST_OPTION = + Compute.SubnetworkListOption.filter(SUBNETWORK_FILTER); + private static final Compute.SubnetworkAggregatedListOption SUBNETWORK_AGGREGATED_LIST_OPTION = + Compute.SubnetworkAggregatedListOption.filter(SUBNETWORK_FILTER); + private static final Compute.NetworkOption NETWORK_OPTION = + Compute.NetworkOption.fields(); + private static final Compute.NetworkFilter NETWORK_FILTER = + Compute.NetworkFilter.equals(Compute.NetworkField.SELF_LINK, "selfLink"); + private static final Compute.NetworkListOption NETWORK_LIST_OPTION = + Compute.NetworkListOption.filter(NETWORK_FILTER); @Test public void testServiceOptions() throws Exception { @@ -246,15 +270,18 @@ public void testModelAndRequests() throws Exception { ADDRESS_INFO, ADDRESS, DISK_ID, SNAPSHOT_ID, SNAPSHOT_INFO, SNAPSHOT, IMAGE_ID, DISK_IMAGE_CONFIGURATION, STORAGE_IMAGE_CONFIGURATION, IMAGE_INFO, IMAGE, STANDARD_DISK_CONFIGURATION, IMAGE_DISK_CONFIGURATION, SNAPSHOT_DISK_CONFIGURATION, - DISK_INFO, DISK, SUBNETWORK_ID, NETWORK_ID, SUBNETWORK_INFO, DISK_TYPE_OPTION, - DISK_TYPE_FILTER, DISK_TYPE_LIST_OPTION, DISK_TYPE_AGGREGATED_LIST_OPTION, + DISK_INFO, DISK, SUBNETWORK_ID, NETWORK_ID, SUBNETWORK_INFO, SUBNETWORK, + STANDARD_NETWORK_CONFIGURATION, SUBNET_NETWORK_CONFIGURATION, NETWORK_INFO, NETWORK, + DISK_TYPE_OPTION, DISK_TYPE_FILTER, DISK_TYPE_LIST_OPTION, DISK_TYPE_AGGREGATED_LIST_OPTION, MACHINE_TYPE_OPTION, MACHINE_TYPE_FILTER, MACHINE_TYPE_LIST_OPTION, MACHINE_TYPE_AGGREGATED_LIST_OPTION, REGION_OPTION, REGION_FILTER, REGION_LIST_OPTION, ZONE_OPTION, ZONE_FILTER, ZONE_LIST_OPTION, LICENSE_OPTION, OPERATION_OPTION, OPERATION_FILTER, OPERATION_LIST_OPTION, ADDRESS_OPTION, ADDRESS_FILTER, ADDRESS_LIST_OPTION, ADDRESS_AGGREGATED_LIST_OPTION, SNAPSHOT_OPTION, SNAPSHOT_FILTER, SNAPSHOT_LIST_OPTION, IMAGE_OPTION, IMAGE_FILTER, IMAGE_LIST_OPTION, DISK_OPTION, - DISK_FILTER, DISK_LIST_OPTION, DISK_AGGREGATED_LIST_OPTION}; + DISK_FILTER, DISK_LIST_OPTION, DISK_AGGREGATED_LIST_OPTION, SUBNETWORK_OPTION, + SUBNETWORK_FILTER, SUBNETWORK_LIST_OPTION, SUBNETWORK_AGGREGATED_LIST_OPTION, + NETWORK_OPTION, NETWORK_FILTER, NETWORK_LIST_OPTION}; for (Serializable obj : objects) { Object copy = serializeAndDeserialize(obj); assertEquals(obj, obj); diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SubnetworkTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SubnetworkTest.java new file mode 100644 index 000000000000..4e47c9aa1198 --- /dev/null +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SubnetworkTest.java @@ -0,0 +1,210 @@ +/* + * 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 org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.createStrictMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class SubnetworkTest { + + private static final String ID = "42"; + private static final Long CREATION_TIMESTAMP = 1453293540000L; + private static final String DESCRIPTION = "description"; + private static final SubnetworkId SUBNETWORK_ID = SubnetworkId.of("project", "region", "network"); + private static final String GATEWAY_ADDRESS = "192.168.1.1"; + private static final NetworkId NETWORK_ID = NetworkId.of("project", "network"); + private static final String IP_RANGE = "192.168.0.0/16"; + + private final Compute serviceMockReturnsOptions = createStrictMock(Compute.class); + private final ComputeOptions mockOptions = createMock(ComputeOptions.class); + private Compute compute; + private Subnetwork subnetwork; + private Subnetwork expectedSubnetwork; + + private void initializeExpectedSubnetwork(int optionsCalls) { + expect(serviceMockReturnsOptions.options()).andReturn(mockOptions).times(optionsCalls); + replay(serviceMockReturnsOptions); + expectedSubnetwork = + new Subnetwork.Builder(serviceMockReturnsOptions, SUBNETWORK_ID, NETWORK_ID, IP_RANGE) + .id(ID) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .gatewayAddress(GATEWAY_ADDRESS) + .build(); + compute = createStrictMock(Compute.class); + } + + private void initializeSubnetwork() { + subnetwork = + new Subnetwork.Builder(compute, SUBNETWORK_ID, NETWORK_ID, IP_RANGE) + .id(ID) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .gatewayAddress(GATEWAY_ADDRESS) + .build(); + } + + @Test + public void testToBuilder() { + initializeExpectedSubnetwork(8); + compareSubnetwork(expectedSubnetwork, expectedSubnetwork.toBuilder().build()); + Subnetwork newSubnetwork = expectedSubnetwork.toBuilder().description("newDescription").build(); + assertEquals("newDescription", newSubnetwork.description()); + newSubnetwork = newSubnetwork.toBuilder().description("description").build(); + compareSubnetwork(expectedSubnetwork, newSubnetwork); + } + + @Test + public void testToBuilderIncomplete() { + initializeExpectedSubnetwork(5); + SubnetworkInfo subnetworkInfo = SubnetworkInfo.of(SUBNETWORK_ID, NETWORK_ID, IP_RANGE); + Subnetwork subnetwork = + new Subnetwork(serviceMockReturnsOptions, new SubnetworkInfo.BuilderImpl(subnetworkInfo)); + compareSubnetwork(subnetwork, subnetwork.toBuilder().build()); + } + + @Test + public void testBuilder() { + initializeExpectedSubnetwork(1); + assertEquals(ID, expectedSubnetwork.id()); + assertEquals(SUBNETWORK_ID, expectedSubnetwork.subnetworkId()); + assertEquals(CREATION_TIMESTAMP, expectedSubnetwork.creationTimestamp()); + assertEquals(DESCRIPTION, expectedSubnetwork.description()); + assertEquals(GATEWAY_ADDRESS, expectedSubnetwork.gatewayAddress()); + assertEquals(NETWORK_ID, expectedSubnetwork.network()); + assertEquals(IP_RANGE, expectedSubnetwork.ipRange()); + assertSame(serviceMockReturnsOptions, expectedSubnetwork.compute()); + } + + @Test + public void testToAndFromPb() { + initializeExpectedSubnetwork(8); + compareSubnetwork(expectedSubnetwork, + Subnetwork.fromPb(serviceMockReturnsOptions, expectedSubnetwork.toPb())); + Subnetwork subnetwork = + new Subnetwork.Builder(serviceMockReturnsOptions, SUBNETWORK_ID, NETWORK_ID, IP_RANGE) + .build(); + compareSubnetwork(subnetwork, Subnetwork.fromPb(serviceMockReturnsOptions, subnetwork.toPb())); + } + + @Test + public void testDeleteOperation() { + initializeExpectedSubnetwork(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(GlobalOperationId.of("project", "op")) + .build(); + expect(compute.delete(SUBNETWORK_ID)).andReturn(operation); + replay(compute); + initializeSubnetwork(); + assertSame(operation, subnetwork.delete()); + } + + @Test + public void testDeleteNull() { + initializeExpectedSubnetwork(1); + expect(compute.options()).andReturn(mockOptions); + expect(compute.delete(SUBNETWORK_ID)).andReturn(null); + replay(compute); + initializeSubnetwork(); + assertNull(subnetwork.delete()); + } + + @Test + public void testExists_True() throws Exception { + initializeExpectedSubnetwork(1); + Compute.SubnetworkOption[] expectedOptions = {Compute.SubnetworkOption.fields()}; + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(SUBNETWORK_ID, expectedOptions)) + .andReturn(expectedSubnetwork); + replay(compute); + initializeSubnetwork(); + assertTrue(subnetwork.exists()); + verify(compute); + } + + @Test + public void testExists_False() throws Exception { + initializeExpectedSubnetwork(1); + Compute.SubnetworkOption[] expectedOptions = {Compute.SubnetworkOption.fields()}; + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(SUBNETWORK_ID, expectedOptions)).andReturn(null); + replay(compute); + initializeSubnetwork(); + assertFalse(subnetwork.exists()); + verify(compute); + } + + @Test + public void testReload() throws Exception { + initializeExpectedSubnetwork(3); + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(SUBNETWORK_ID)).andReturn(expectedSubnetwork); + replay(compute); + initializeSubnetwork(); + Subnetwork updatedSubnetwork = subnetwork.reload(); + compareSubnetwork(expectedSubnetwork, updatedSubnetwork); + verify(compute); + } + + @Test + public void testReloadNull() throws Exception { + initializeExpectedSubnetwork(1); + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(SUBNETWORK_ID)).andReturn(null); + replay(compute); + initializeSubnetwork(); + assertNull(subnetwork.reload()); + verify(compute); + } + + @Test + public void testReloadWithOptions() throws Exception { + initializeExpectedSubnetwork(3); + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(SUBNETWORK_ID, Compute.SubnetworkOption.fields())) + .andReturn(expectedSubnetwork); + replay(compute); + initializeSubnetwork(); + Subnetwork updatedSubnetwork = subnetwork.reload(Compute.SubnetworkOption.fields()); + compareSubnetwork(expectedSubnetwork, updatedSubnetwork); + verify(compute); + } + + public void compareSubnetwork(Subnetwork expected, Subnetwork value) { + assertEquals(expected, value); + assertEquals(expected.compute().options(), value.compute().options()); + assertEquals(expected.id(), value.id()); + assertEquals(expected.subnetworkId(), value.subnetworkId()); + assertEquals(expected.creationTimestamp(), value.creationTimestamp()); + assertEquals(expected.description(), value.description()); + assertEquals(expected.gatewayAddress(), value.gatewayAddress()); + assertEquals(expected.network(), value.network()); + assertEquals(expected.ipRange(), value.ipRange()); + assertEquals(expected.hashCode(), value.hashCode()); + } +} diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/it/ITComputeTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/it/ITComputeTest.java index 39fdb622a59d..aa94baf9809e 100644 --- a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/it/ITComputeTest.java +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/it/ITComputeTest.java @@ -46,6 +46,10 @@ import com.google.gcloud.compute.License; import com.google.gcloud.compute.LicenseId; import com.google.gcloud.compute.MachineType; +import com.google.gcloud.compute.Network; +import com.google.gcloud.compute.NetworkConfiguration; +import com.google.gcloud.compute.NetworkId; +import com.google.gcloud.compute.NetworkInfo; import com.google.gcloud.compute.Operation; import com.google.gcloud.compute.Region; import com.google.gcloud.compute.RegionAddressId; @@ -55,7 +59,12 @@ import com.google.gcloud.compute.SnapshotId; import com.google.gcloud.compute.SnapshotInfo; import com.google.gcloud.compute.StandardDiskConfiguration; +import com.google.gcloud.compute.StandardNetworkConfiguration; import com.google.gcloud.compute.StorageImageConfiguration; +import com.google.gcloud.compute.SubnetNetworkConfiguration; +import com.google.gcloud.compute.Subnetwork; +import com.google.gcloud.compute.SubnetworkId; +import com.google.gcloud.compute.SubnetworkInfo; import com.google.gcloud.compute.Zone; import com.google.gcloud.compute.ZoneOperationId; import com.google.gcloud.compute.testing.RemoteComputeHelper; @@ -1353,4 +1362,241 @@ public void testListImagesWithFilter() { } assertTrue(count > 0); } + + @Test + public void testCreateAndGetNetwork() throws InterruptedException { + String name = BASE_RESOURCE_NAME + "create-and-get-network"; + NetworkId networkId = NetworkId.of(name); + NetworkInfo networkInfo = + NetworkInfo.of(networkId, StandardNetworkConfiguration.of("192.168.0.0/16")); + Operation operation = compute.create(networkInfo); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + // test get network with selected fields + Network network = compute.getNetwork(networkId.network(), + Compute.NetworkOption.fields(Compute.NetworkField.CREATION_TIMESTAMP)); + assertEquals(networkId.network(), network.networkId().network()); + assertNull(network.id()); + assertNotNull(network.creationTimestamp()); + assertNull(network.description()); + assertEquals(NetworkConfiguration.Type.STANDARD, network.configuration().type()); + StandardNetworkConfiguration remoteConfiguration = network.configuration(); + assertEquals("192.168.0.0/16", remoteConfiguration.ipRange()); + // test get network + network = compute.getNetwork(networkId.network()); + assertEquals(networkId.network(), network.networkId().network()); + assertNotNull(network.id()); + assertNotNull(network.creationTimestamp()); + assertEquals(NetworkConfiguration.Type.STANDARD, network.configuration().type()); + remoteConfiguration = network.configuration(); + assertEquals("192.168.0.0/16", remoteConfiguration.ipRange()); + operation = network.delete(); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + assertNull(compute.getNetwork(name)); + } + + @Test + public void testListNetworks() throws InterruptedException { + String name = BASE_RESOURCE_NAME + "list-network"; + NetworkId networkId = NetworkId.of(name); + NetworkInfo networkInfo = + NetworkInfo.of(networkId, StandardNetworkConfiguration.of("192.168.0.0/16")); + Operation operation = compute.create(networkInfo); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + // test list + Compute.NetworkFilter filter = Compute.NetworkFilter.equals(Compute.NetworkField.NAME, name); + Page networkPage = compute.listNetworks(Compute.NetworkListOption.filter(filter)); + Iterator networkIterator = networkPage.iterateAll(); + int count = 0; + while (networkIterator.hasNext()) { + Network network = networkIterator.next(); + assertEquals(networkId.network(), network.networkId().network()); + assertNotNull(network.id()); + assertNotNull(network.creationTimestamp()); + assertEquals(NetworkConfiguration.Type.STANDARD, network.configuration().type()); + StandardNetworkConfiguration remoteConfiguration = network.configuration(); + assertEquals("192.168.0.0/16", remoteConfiguration.ipRange()); + count++; + } + assertEquals(1, count); + // test list with selected fields + count = 0; + networkPage = compute.listNetworks(Compute.NetworkListOption.filter(filter), + Compute.NetworkListOption.fields(Compute.NetworkField.CREATION_TIMESTAMP)); + networkIterator = networkPage.iterateAll(); + while (networkIterator.hasNext()) { + Network network = networkIterator.next(); + assertEquals(networkId.network(), network.networkId().network()); + assertNull(network.id()); + assertNotNull(network.creationTimestamp()); + assertNull(network.description()); + assertEquals(NetworkConfiguration.Type.STANDARD, network.configuration().type()); + StandardNetworkConfiguration remoteConfiguration = network.configuration(); + assertEquals("192.168.0.0/16", remoteConfiguration.ipRange()); + count++; + } + assertEquals(1, count); + operation = compute.deleteNetwork(networkId); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + assertNull(compute.getNetwork(name)); + } + + @Test + public void testCreateNetworkAndSubnetwork() throws InterruptedException { + String networkName = BASE_RESOURCE_NAME + "create-subnetwork-network"; + NetworkId networkId = NetworkId.of(networkName); + NetworkInfo networkInfo = NetworkInfo.of(networkId, SubnetNetworkConfiguration.of(false)); + Operation operation = compute.create(networkInfo); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + // test get network + Network network = compute.getNetwork(networkId.network()); + assertEquals(networkId.network(), network.networkId().network()); + assertNotNull(network.id()); + assertNotNull(network.creationTimestamp()); + assertEquals(NetworkConfiguration.Type.SUBNET, network.configuration().type()); + assertTrue(network.configuration() instanceof SubnetNetworkConfiguration); + assertFalse(network.configuration().autoCreateSubnetworks()); + String subnetworkName = BASE_RESOURCE_NAME + "create-subnetwork-subnetwork"; + SubnetworkId subnetworkId = SubnetworkId.of(REGION, subnetworkName); + SubnetworkInfo subnetworkInfo = SubnetworkInfo.of(subnetworkId, networkId, "192.168.0.0/16"); + operation = compute.create(subnetworkInfo); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + // test get subnetwork with selected fields + Subnetwork subnetwork = compute.get(subnetworkId, + Compute.SubnetworkOption.fields(Compute.SubnetworkField.CREATION_TIMESTAMP)); + assertNull(subnetwork.id()); + assertEquals(subnetworkId.subnetwork(), subnetwork.subnetworkId().subnetwork()); + assertNotNull(subnetwork.creationTimestamp()); + assertNull(subnetwork.description()); + assertNull(subnetwork.gatewayAddress()); + assertNull(subnetwork.network()); + assertNull(subnetwork.ipRange()); + // test get subnetwork + subnetwork = compute.get(subnetworkId); + assertNotNull(subnetwork.id()); + assertEquals(subnetworkId.subnetwork(), subnetwork.subnetworkId().subnetwork()); + assertNotNull(subnetwork.creationTimestamp()); + assertNotNull(subnetwork.gatewayAddress()); + assertEquals(networkId.network(), subnetwork.network().network()); + assertEquals("192.168.0.0/16", subnetwork.ipRange()); + // test list subnetworks + Compute.SubnetworkFilter filter = + Compute.SubnetworkFilter.equals(Compute.SubnetworkField.NAME, subnetworkName); + Page subnetworkPage = + compute.listSubnetworks(REGION, Compute.SubnetworkListOption.filter(filter)); + Iterator subnetworkIterator = subnetworkPage.iterateAll(); + int count = 0; + while (subnetworkIterator.hasNext()) { + Subnetwork remoteSubnetwork = subnetworkIterator.next(); + assertNotNull(remoteSubnetwork.id()); + assertEquals(subnetworkId.subnetwork(), remoteSubnetwork.subnetworkId().subnetwork()); + assertNotNull(remoteSubnetwork.creationTimestamp()); + assertNotNull(remoteSubnetwork.gatewayAddress()); + assertEquals(networkId.network(), remoteSubnetwork.network().network()); + assertEquals("192.168.0.0/16", remoteSubnetwork.ipRange()); + count++; + } + assertEquals(1, count); + // test list subnetworks with selected fields + subnetworkPage = compute.listSubnetworks(REGION, Compute.SubnetworkListOption.filter(filter), + Compute.SubnetworkListOption.fields(Compute.SubnetworkField.CREATION_TIMESTAMP)); + subnetworkIterator = subnetworkPage.iterateAll(); + count = 0; + while (subnetworkIterator.hasNext()) { + Subnetwork remoteSubnetwork = subnetworkIterator.next(); + assertNull(remoteSubnetwork.id()); + assertEquals(subnetworkId.subnetwork(), remoteSubnetwork.subnetworkId().subnetwork()); + assertNotNull(remoteSubnetwork.creationTimestamp()); + assertNull(remoteSubnetwork.description()); + assertNull(remoteSubnetwork.gatewayAddress()); + assertNull(remoteSubnetwork.network()); + assertNull(remoteSubnetwork.ipRange()); + count++; + } + assertEquals(1, count); + operation = subnetwork.delete(); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + operation = compute.deleteNetwork(networkId); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + assertNull(compute.get(subnetworkId)); + assertNull(compute.getNetwork(networkName)); + } + + @Test + public void testAggregatedListSubnetworks() throws InterruptedException { + String networkName = BASE_RESOURCE_NAME + "list-subnetwork-network"; + NetworkId networkId = NetworkId.of(networkName); + NetworkInfo networkInfo = NetworkInfo.of(networkId, SubnetNetworkConfiguration.of(false)); + Operation operation = compute.create(networkInfo); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + String prefix = BASE_RESOURCE_NAME + "list-subnetwork"; + String[] regionNames = {"us-central1", "us-east1"}; + String[] subnetworkNames = {prefix + "1", prefix + "2"}; + String[] ipRanges = {"10.128.0.0/20", "10.132.0.0/20"}; + SubnetworkId firstSubnetworkId = SubnetworkId.of(regionNames[0], subnetworkNames[0]); + SubnetworkId secondSubnetworkId = SubnetworkId.of(regionNames[1], subnetworkNames[1]); + SubnetworkInfo firstSubnetworkInfo = + SubnetworkInfo.of(firstSubnetworkId, networkId, ipRanges[0]); + SubnetworkInfo secondSubnetworkInfo = + SubnetworkInfo.of(secondSubnetworkId, networkId, ipRanges[1]); + Operation firstOperation = compute.create(firstSubnetworkInfo); + Operation secondOperation = compute.create(secondSubnetworkInfo); + while (!firstOperation.isDone()) { + Thread.sleep(1000L); + } + while (!secondOperation.isDone()) { + Thread.sleep(1000L); + } + Set regionSet = ImmutableSet.copyOf(regionNames); + Set subnetworkSet = ImmutableSet.copyOf(subnetworkNames); + Set rangeSet = ImmutableSet.copyOf(ipRanges); + Compute.SubnetworkFilter subnetworkFilter = + Compute.SubnetworkFilter.equals(Compute.SubnetworkField.NAME, prefix + "\\d"); + Page subnetworkPage = + compute.listSubnetworks(Compute.SubnetworkAggregatedListOption.filter(subnetworkFilter)); + Iterator subnetworkIterator = subnetworkPage.iterateAll(); + int count = 0; + while (subnetworkIterator.hasNext()) { + Subnetwork remoteSubnetwork = subnetworkIterator.next(); + assertNotNull(remoteSubnetwork.id()); + assertTrue(regionSet.contains(remoteSubnetwork.subnetworkId().region())); + assertTrue(subnetworkSet.contains(remoteSubnetwork.subnetworkId().subnetwork())); + assertNotNull(remoteSubnetwork.creationTimestamp()); + assertNotNull(remoteSubnetwork.gatewayAddress()); + assertEquals(networkId.network(), remoteSubnetwork.network().network()); + assertTrue(rangeSet.contains(remoteSubnetwork.ipRange())); + count++; + } + assertEquals(2, count); + firstOperation = compute.delete(firstSubnetworkId); + secondOperation = compute.delete(secondSubnetworkId); + while (!firstOperation.isDone()) { + Thread.sleep(1000L); + } + while (!secondOperation.isDone()) { + Thread.sleep(1000L); + } + operation = compute.deleteNetwork(networkId); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + assertNull(compute.getNetwork(networkName)); + } }