From 7fd1d13311f36cfdeb1656e5e842d33133035ed3 Mon Sep 17 00:00:00 2001 From: Marco Ziccardi Date: Wed, 27 Apr 2016 16:54:02 +0200 Subject: [PATCH] Add functional methods for instances, Instance class and tests (#959) --- .../com/google/gcloud/compute/Compute.java | 389 ++++++++ .../google/gcloud/compute/ComputeImpl.java | 437 ++++++++- .../com/google/gcloud/compute/Instance.java | 465 +++++++++ .../google/gcloud/compute/spi/ComputeRpc.java | 173 ++++ .../gcloud/compute/spi/DefaultComputeRpc.java | 261 +++++ .../gcloud/compute/ComputeImplTest.java | 816 ++++++++++++++++ .../google/gcloud/compute/InstanceTest.java | 895 ++++++++++++++++++ .../gcloud/compute/SerializationTest.java | 16 +- .../gcloud/compute/it/ITComputeTest.java | 320 +++++++ 9 files changed, 3769 insertions(+), 3 deletions(-) create mode 100644 gcloud-java-compute/src/main/java/com/google/gcloud/compute/Instance.java create mode 100644 gcloud-java-compute/src/test/java/com/google/gcloud/compute/InstanceTest.java 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 907f581fcca6..0512a1554ee0 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 @@ -23,6 +23,8 @@ import com.google.common.collect.Sets; import com.google.gcloud.Page; import com.google.gcloud.Service; +import com.google.gcloud.compute.AttachedDisk.PersistentDiskConfiguration; +import com.google.gcloud.compute.NetworkInterface.AccessConfig; import com.google.gcloud.compute.spi.ComputeRpc; import java.io.Serializable; @@ -520,6 +522,51 @@ static String selector(NetworkField... fields) { } } + /** + * Fields of a Compute Engine Instance resource. + * + * @see + * Network Resource + */ + enum InstanceField { + CAN_IP_FORWARD("canIpForward"), + CPU_PLATFORM("cpuPlatform"), + CREATION_TIMESTAMP("creationTimestamp"), + DESCRIPTION("description"), + DISKS("disks"), + ID("id"), + MACHINE_TYPE("machineType"), + METADATA("metadata"), + NAME("name"), + NETWORK_INTERFACES("networkInterfaces"), + SCHEDULING("scheduling"), + SELF_LINK("selfLink"), + SERVICE_ACCOUNTS("serviceAccounts"), + STATUS("status"), + STATUS_MESSAGE("statusMessage"), + TAGS("tags"), + ZONE("zone"); + + private final String selector; + + InstanceField(String selector) { + this.selector = selector; + } + + public String selector() { + return selector; + } + + static String selector(InstanceField... fields) { + Set fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 1); + fieldStrings.add(SELF_LINK.selector()); + for (InstanceField field : fields) { + fieldStrings.add(field.selector()); + } + return Joiner.on(',').join(fieldStrings); + } + } + /** * Base class for list filters. */ @@ -1045,6 +1092,54 @@ public static NetworkFilter notEquals(NetworkField field, boolean value) { } } + /** + * Class for filtering instance lists. + */ + class InstanceFilter extends ListFilter { + + private static final long serialVersionUID = 679008888882025686L; + + private InstanceFilter(InstanceField 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 InstanceFilter equals(InstanceField field, String value) { + return new InstanceFilter(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 InstanceFilter notEquals(InstanceField field, String value) { + return new InstanceFilter(checkNotNull(field), ComparisonOperator.NE, checkNotNull(value)); + } + + /** + * Returns a equals filter for the given field and boolean value. + */ + public static InstanceFilter equals(InstanceField field, boolean value) { + return new InstanceFilter(checkNotNull(field), ComparisonOperator.EQ, value); + } + + /** + * Returns a not-equals filter for the given field and boolean value. + */ + public static InstanceFilter notEquals(InstanceField field, boolean value) { + return new InstanceFilter(checkNotNull(field), ComparisonOperator.EQ, value); + } + } + /** * Class for specifying disk type get options. */ @@ -1989,6 +2084,108 @@ public static NetworkListOption fields(NetworkField... fields) { } } + /** + * Class for specifying instance get options. + */ + class InstanceOption extends Option { + + private static final long serialVersionUID = -5277658025892081493L; + + private InstanceOption(ComputeRpc.Option option, Object value) { + super(option, value); + } + + /** + * Returns an option to specify the instance's fields to be returned by the RPC call. If this + * option is not provided, all instance's fields are returned. {@code InstanceOption.fields} + * can be used to specify only the fields of interest. {@link Instance#instanceId()} is always + * returned, even if not specified. + */ + public static InstanceOption fields(InstanceField... fields) { + return new InstanceOption(ComputeRpc.Option.FIELDS, InstanceField.selector(fields)); + } + } + + /** + * Class for specifying instance list options. + */ + class InstanceListOption extends Option { + + private static final long serialVersionUID = -1096684312959047430L; + + private InstanceListOption(ComputeRpc.Option option, Object value) { + super(option, value); + } + + /** + * Returns an option to specify a filter on the instances being listed. + */ + public static InstanceListOption filter(InstanceFilter filter) { + return new InstanceListOption(ComputeRpc.Option.FILTER, filter.toPb()); + } + + /** + * Returns an option to specify the maximum number of instances returned per page. + * {@code pageSize} must be between 0 and 500 (inclusive). If not specified 500 is used. + */ + public static InstanceListOption pageSize(long pageSize) { + return new InstanceListOption(ComputeRpc.Option.MAX_RESULTS, pageSize); + } + + /** + * Returns an option to specify the page token from which to start listing instances. + */ + public static InstanceListOption pageToken(String pageToken) { + return new InstanceListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken); + } + + /** + * Returns an option to specify the instance's fields to be returned by the RPC call. If this + * option is not provided, all instance's fields are returned. {@code InstanceListOption.fields} + * can be used to specify only the fields of interest. {@link Instance#instanceId()} is always + * returned, even if not specified. + */ + public static InstanceListOption fields(InstanceField... fields) { + StringBuilder builder = new StringBuilder(); + builder.append("items(").append(InstanceField.selector(fields)).append("),nextPageToken"); + return new InstanceListOption(ComputeRpc.Option.FIELDS, builder.toString()); + } + } + + /** + * Class for specifying instance aggregated list options. + */ + class InstanceAggregatedListOption extends Option { + + private static final long serialVersionUID = -2020005298975967713L; + + private InstanceAggregatedListOption(ComputeRpc.Option option, Object value) { + super(option, value); + } + + /** + * Returns an option to specify a filter on the instances being listed. + */ + public static InstanceAggregatedListOption filter(InstanceFilter filter) { + return new InstanceAggregatedListOption(ComputeRpc.Option.FILTER, filter.toPb()); + } + + /** + * Returns an option to specify the maximum number of instances returned per page. + * {@code pageSize} must be between 0 and 500 (inclusive). If not specified 500 is used. + */ + public static InstanceAggregatedListOption pageSize(long pageSize) { + return new InstanceAggregatedListOption(ComputeRpc.Option.MAX_RESULTS, pageSize); + } + + /** + * Returns an option to specify the page token from which to start listing instances. + */ + public static InstanceAggregatedListOption pageToken(String pageToken) { + return new InstanceAggregatedListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken); + } + } + /** * Returns the requested disk type or {@code null} if not found. * @@ -2397,4 +2594,196 @@ Operation deprecate(ImageId image, DeprecationStatus deprecationStatus, * @throws ComputeException upon failure */ Operation deleteNetwork(NetworkId network, OperationOption... options); + + /** + * Creates a new instance. + * + * @return a zone operation for instance's creation + * @throws ComputeException upon failure + */ + Operation create(InstanceInfo instance, OperationOption... options); + + /** + * Returns the requested instance or {@code null} if not found. + * + * @throws ComputeException upon failure + */ + Instance get(InstanceId instance, InstanceOption... options); + + /** + * Lists instances for the provided zone. + * + * @throws ComputeException upon failure + */ + Page listInstances(String zone, InstanceListOption... options); + + /** + * Lists instances for all zones. + * + * @throws ComputeException upon failure + */ + Page listInstances(InstanceAggregatedListOption... options); + + /** + * Deletes the requested instance. + * + * @return a zone operation if the delete request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation delete(InstanceId instance, OperationOption... options); + + /** + * Adds an access configuration to an instance's network interface. + * + * @return a zone operation if the add request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + Operation addAccessConfig(InstanceId instance, String networkInterface, AccessConfig accessConfig, + OperationOption... options); + + /** + * Attaches a persistent disk to an instance given its configuration. + * + * @return a zone operation if the attach request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation attachDisk(InstanceId instance, PersistentDiskConfiguration configuration, + OperationOption... options); + + /** + * Attaches a persistent disk to an instance given the device name and its configuration. + * + * @return a zone operation if the attach request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation attachDisk(InstanceId instance, String deviceName, + PersistentDiskConfiguration configuration, OperationOption... options); + + /** + * Attaches a persistent disk to an instance given the device name, its configuration and the + * device index. + * + * @return a zone operation if the attach request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation attachDisk(InstanceId instance, String deviceName, + PersistentDiskConfiguration configuration, int index, OperationOption... options); + + /** + * Deletes an access configuration from an instance's network interface. + * + * @return a zone operation if the delete request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation deleteAccessConfig(InstanceId instance, String networkInterface, String accessConfig, + OperationOption... options); + + /** + * Detaches a disk from an instance. + * + * @return a zone operation if the detach request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation detachDisk(InstanceId instance, String deviceName, OperationOption... options); + + /** + * Returns the serial port output for the provided instance and port number. {@code port} must be + * between 1 and 4 (inclusive). + * + * @return the serial port output or {@code null} if the instance was not found + * @throws ComputeException upon failure + */ + String getSerialPortOutput(InstanceId instance, int port); + + /** + * Returns the default serial port output for the provided instance. Default serial port + * corresponds to port number 1. + * + * @return the serial port output or {@code null} if the instance was not found + * @throws ComputeException upon failure + */ + String getSerialPortOutput(InstanceId instance); + + /** + * Resets the provided instance. + * + * @return a zone operation if the reset request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation reset(InstanceId instance, OperationOption... options); + + /** + * Sets the auto-delete flag for a disk attached to the provided instance. + * + * @return a zone operation if the flag setting request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation setDiskAutoDelete(InstanceId instance, String deviceName, boolean autoDelete, + OperationOption... options); + + /** + * Sets the machine type for the provided instance. Instance must be in + * {@link InstanceInfo.Status#TERMINATED} state to be able to set its machine type. + * + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + Operation setMachineType(InstanceId instance, MachineTypeId machineType, + OperationOption... options); + + /** + * Sets the metadata for the provided instance. + * + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + Operation setMetadata(InstanceId instance, Metadata metadata, OperationOption... options); + + /** + * Sets the scheduling options for the provided instance. + * + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + Operation setSchedulingOptions(InstanceId instance, SchedulingOptions scheduling, + OperationOption... options); + + /** + * Sets the tags for the provided instance. + * + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + Operation setTags(InstanceId instance, Tags tags, OperationOption... options); + + /** + * Starts the provided instance. + * + * @return a zone operation if the start request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation start(InstanceId instance, OperationOption... options); + + /** + * Stops the provided instance. + * + * @return a zone operation if the stop request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + Operation stop(InstanceId instance, 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 d8ac3a840761..3a8f46a88265 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 @@ -28,6 +28,8 @@ import com.google.gcloud.PageImpl; import com.google.gcloud.PageImpl.NextPageFetcher; import com.google.gcloud.RetryHelper; +import com.google.gcloud.compute.AttachedDisk.PersistentDiskConfiguration; +import com.google.gcloud.compute.NetworkInterface.AccessConfig; import com.google.gcloud.compute.spi.ComputeRpc; import java.util.Map; @@ -412,6 +414,46 @@ public Page nextPage() { } } + private static class InstancePageFetcher implements NextPageFetcher { + + private static final long serialVersionUID = 7563769742657453865L; + private final Map requestOptions; + private final ComputeOptions serviceOptions; + private final String zone; + + InstancePageFetcher(String zone, ComputeOptions serviceOptions, String cursor, + Map optionMap) { + this.requestOptions = + PageImpl.nextRequestOptions(ComputeRpc.Option.PAGE_TOKEN, cursor, optionMap); + this.serviceOptions = serviceOptions; + this.zone = zone; + } + + @Override + public Page nextPage() { + return listInstances(zone, serviceOptions, requestOptions); + } + } + + private static class AggregatedInstancePageFetcher implements NextPageFetcher { + + private static final long serialVersionUID = 1863059389783095681L; + private final Map requestOptions; + private final ComputeOptions serviceOptions; + + AggregatedInstancePageFetcher(ComputeOptions serviceOptions, String cursor, + Map optionMap) { + this.requestOptions = + PageImpl.nextRequestOptions(ComputeRpc.Option.PAGE_TOKEN, cursor, optionMap); + this.serviceOptions = serviceOptions; + } + + @Override + public Page nextPage() { + return listInstances(serviceOptions, requestOptions); + } + } + private final ComputeRpc computeRpc; ComputeImpl(ComputeOptions options) { @@ -1431,7 +1473,7 @@ public com.google.api.services.compute.model.Subnetwork call() { } private static Function - subnetworkFromPb(final ComputeOptions serviceOptions) { + subnetworkFromPb(final ComputeOptions serviceOptions) { return new Function() { @Override public Subnetwork apply(com.google.api.services.compute.model.Subnetwork subnetwork) { @@ -1605,6 +1647,399 @@ public Operation deleteNetwork(String network, OperationOption... options) { return deleteNetwork(NetworkId.of(network)); } + @Override + public Operation create(InstanceInfo instance, OperationOption... options) { + final InstanceInfo completeInstance = instance.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.createInstance(completeInstance.instanceId().zone(), + completeInstance.toPb(), optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Instance get(final InstanceId instance, InstanceOption... options) { + final Map optionsMap = optionMap(options); + try { + com.google.api.services.compute.model.Instance answer = + runWithRetries(new Callable() { + @Override + public com.google.api.services.compute.model.Instance call() { + return computeRpc.getInstance(instance.zone(), instance.instance(), optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Instance.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + private static Function + instanceFromPb(final ComputeOptions serviceOptions) { + return new Function() { + @Override + public Instance apply(com.google.api.services.compute.model.Instance instance) { + return Instance.fromPb(serviceOptions.service(), instance); + } + }; + } + + @Override + public Page listInstances(String zone, InstanceListOption... options) { + return listInstances(zone, options(), optionMap(options)); + } + + private static Page listInstances(final String zone, + final ComputeOptions serviceOptions, final Map optionsMap) { + try { + ComputeRpc.Tuple> result = + runWithRetries(new Callable>>() { + @Override + public ComputeRpc.Tuple> call() { + return serviceOptions.rpc().listInstances(zone, optionsMap); + } + }, serviceOptions.retryParams(), EXCEPTION_HANDLER); + String cursor = result.x(); + Iterable instances = Iterables.transform( + result.y() == null ? ImmutableList.of() + : result.y(), instanceFromPb(serviceOptions)); + return new PageImpl<>(new InstancePageFetcher(zone, serviceOptions, cursor, optionsMap), + cursor, instances); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Page listInstances(InstanceAggregatedListOption... options) { + return listInstances(options(), optionMap(options)); + } + + private static Page listInstances(final ComputeOptions serviceOptions, + final Map optionsMap) { + try { + ComputeRpc.Tuple> result = + runWithRetries(new Callable>>() { + @Override + public ComputeRpc.Tuple> call() { + return serviceOptions.rpc().listInstances(optionsMap); + } + }, serviceOptions.retryParams(), EXCEPTION_HANDLER); + String cursor = result.x(); + Iterable instances = Iterables.transform( + result.y() == null ? ImmutableList.of() + : result.y(), instanceFromPb(serviceOptions)); + return new PageImpl<>(new AggregatedInstancePageFetcher(serviceOptions, cursor, optionsMap), + cursor, instances); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation delete(final InstanceId instance, 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.deleteInstance(instance.zone(), instance.instance(), optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation addAccessConfig(final InstanceId instance, final String networkInterface, + final AccessConfig accessConfig, 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.addAccessConfig(instance.zone(), instance.instance(), + networkInterface, accessConfig.toPb(), optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + private Operation attachDisk(final InstanceId instance, AttachedDisk diskToAttach, + OperationOption... options) { + final AttachedDisk completeDisk = diskToAttach.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.attachDisk(instance.zone(), instance.instance(), + completeDisk.toPb(), optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation attachDisk(InstanceId instance, PersistentDiskConfiguration configuration, + OperationOption... options) { + return attachDisk(instance, AttachedDisk.of(configuration), options); + } + + @Override + public Operation attachDisk(InstanceId instance, String deviceName, + PersistentDiskConfiguration configuration, OperationOption... options) { + return attachDisk(instance, AttachedDisk.of(deviceName, configuration), options); + } + + @Override + public Operation attachDisk(InstanceId instance, String deviceName, + PersistentDiskConfiguration configuration, int index, OperationOption... options) { + AttachedDisk attachedDisk = AttachedDisk.builder(configuration) + .deviceName(deviceName) + .index(index) + .build(); + return attachDisk(instance, attachedDisk, options); + } + + @Override + public Operation deleteAccessConfig(final InstanceId instance, final String networkInterface, + final String accessConfig, 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.deleteAccessConfig(instance.zone(), instance.instance(), + networkInterface, accessConfig, optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation detachDisk(final InstanceId instance, final String deviceName, + 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.detachDisk(instance.zone(), instance.instance(), deviceName, + optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public String getSerialPortOutput(final InstanceId instance, final int port) { + try { + return runWithRetries(new Callable() { + @Override + public String call() { + return computeRpc.getSerialPortOutput(instance.zone(), instance.instance(), port, + optionMap()); + } + }, options().retryParams(), EXCEPTION_HANDLER); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public String getSerialPortOutput(final InstanceId instance) { + try { + return runWithRetries(new Callable() { + @Override + public String call() { + return computeRpc.getSerialPortOutput(instance.zone(), instance.instance(), null, + optionMap()); + } + }, options().retryParams(), EXCEPTION_HANDLER); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation reset(final InstanceId instance, 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.reset(instance.zone(), instance.instance(), optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation setDiskAutoDelete(final InstanceId instance, final String deviceName, + final boolean autoDelete, 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.setDiskAutoDelete(instance.zone(), instance.instance(), deviceName, + autoDelete, optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation setMachineType(final InstanceId instance, final MachineTypeId machineType, + OperationOption... options) { + final String machineTypeUrl = machineType.setProjectId(options().projectId()).selfLink(); + 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.setMachineType(instance.zone(), instance.instance(), machineTypeUrl, + optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation setMetadata(final InstanceId instance, final Metadata metadata, + 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.setMetadata(instance.zone(), instance.instance(), metadata.toPb(), + optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation setSchedulingOptions(final InstanceId instance, + final SchedulingOptions schedulingOptions, 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.setScheduling(instance.zone(), instance.instance(), + schedulingOptions.toPb(), optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation setTags(final InstanceId instance, final Tags tags, 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.setTags(instance.zone(), instance.instance(), tags.toPb(), + optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation start(final InstanceId instance, 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.start(instance.zone(), instance.instance(), optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation stop(final InstanceId instance, 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.stop(instance.zone(), instance.instance(), optionsMap); + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + 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/Instance.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Instance.java new file mode 100644 index 000000000000..5f9aee0dd840 --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Instance.java @@ -0,0 +1,465 @@ +/* + * 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.common.collect.ImmutableList; +import com.google.gcloud.compute.AttachedDisk.PersistentDiskConfiguration; +import com.google.gcloud.compute.Compute.InstanceOption; +import com.google.gcloud.compute.Compute.OperationOption; +import com.google.gcloud.compute.NetworkInterface.AccessConfig; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * A Google Compute Engine VM Instance. An instance is a virtual machine (VM) hosted on Google's + * infrastructure. Instances can run Linux and Windows Server images provided by Google, or any + * customized versions of these images. You can also build and run images of other operating + * systems. Objects of this class are immutable. To get an {@code Instance} object with the most + * recent information use {@link #reload}. {@code Instance} adds a layer of service-related + * functionality over {@link InstanceInfo}. + * + * @see Virtual Machine Instances + */ +public class Instance extends InstanceInfo { + + private static final long serialVersionUID = 3072508155558980677L; + + private final ComputeOptions options; + private transient Compute compute; + + /** + * A builder for {@code Instance} objects. + */ + public static class Builder extends InstanceInfo.Builder { + + private final Compute compute; + private final InstanceInfo.BuilderImpl infoBuilder; + + Builder(Compute compute, InstanceId instanceId, MachineTypeId machineType, + AttachedDisk attachedDisk, NetworkInterface networkInterface) { + this.compute = compute; + this.infoBuilder = new InstanceInfo.BuilderImpl(instanceId); + this.infoBuilder.machineType(machineType); + this.infoBuilder.attachedDisks(ImmutableList.of(attachedDisk)); + this.infoBuilder.networkInterfaces(ImmutableList.of(networkInterface)); + } + + Builder(Instance instance) { + this.compute = instance.compute; + this.infoBuilder = new InstanceInfo.BuilderImpl(instance); + } + + @Override + Builder id(String id) { + this.infoBuilder.id(id); + return this; + } + + @Override + public Builder instanceId(InstanceId instanceId) { + this.infoBuilder.instanceId(instanceId); + return this; + } + + @Override + Builder creationTimestamp(Long creationTimestamp) { + this.infoBuilder.creationTimestamp(creationTimestamp); + return this; + } + + @Override + public Builder description(String description) { + this.infoBuilder.description(description); + return this; + } + + @Override + Builder status(Status status) { + this.infoBuilder.status(status); + return this; + } + + @Override + Builder statusMessage(String statusMessage) { + this.infoBuilder.statusMessage(statusMessage); + return this; + } + + @Override + public Builder tags(Tags tags) { + this.infoBuilder.tags(tags); + return this; + } + + @Override + public Builder machineType(MachineTypeId machineType) { + this.infoBuilder.machineType(machineType); + return this; + } + + @Override + public Builder canIpForward(Boolean canIpForward) { + this.infoBuilder.canIpForward(canIpForward); + return this; + } + + @Override + public Builder networkInterfaces(List networkInterfaces) { + this.infoBuilder.networkInterfaces(networkInterfaces); + return this; + } + + @Override + public Builder networkInterfaces(NetworkInterface... networkInterfaces) { + this.infoBuilder.networkInterfaces(networkInterfaces); + return this; + } + + @Override + public Builder attachedDisks(List attachedDisks) { + this.infoBuilder.attachedDisks(attachedDisks); + return this; + } + + @Override + public Builder attachedDisks(AttachedDisk... attachedDisks) { + this.infoBuilder.attachedDisks(attachedDisks); + return this; + } + + @Override + public Builder metadata(Metadata metadata) { + this.infoBuilder.metadata(metadata); + return this; + } + + @Override + public Builder serviceAccounts(List serviceAccounts) { + this.infoBuilder.serviceAccounts(serviceAccounts); + return this; + } + + @Override + public Builder schedulingOptions(SchedulingOptions schedulingOptions) { + this.infoBuilder.schedulingOptions(schedulingOptions); + return this; + } + + @Override + Builder cpuPlatform(String cpuPlatform) { + this.infoBuilder.cpuPlatform(cpuPlatform); + return this; + } + + @Override + public Instance build() { + return new Instance(compute, infoBuilder); + } + } + + Instance(Compute compute, Instance.BuilderImpl infoBuilder) { + super(infoBuilder); + this.compute = checkNotNull(compute); + this.options = compute.options(); + } + + /** + * Checks if this instance exists. + * + * @return {@code true} if this instance exists, {@code false} otherwise + * @throws ComputeException upon failure + */ + public boolean exists() { + return reload(InstanceOption.fields()) != null; + } + + /** + * Fetches current instance's latest information. Returns {@code null} if the instance does not + * exist. + * + * @param options instance options + * @return a {@code Instance} object with latest information or {@code null} if not found + * @throws ComputeException upon failure + */ + public Instance reload(InstanceOption... options) { + return compute.get(instanceId(), options); + } + + /** + * Deletes this instance. + * + * @return a zone operation if delete request was successfully sent, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + public Operation delete(OperationOption... options) { + return compute.delete(instanceId(), options); + } + + /** + * Adds an access configuration to the provided network interface for this instance. + * + * @return a zone operation if the add request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + public Operation addAccessConfig(String networkInterface, AccessConfig accessConfig, + OperationOption... options) { + return compute.addAccessConfig(instanceId(), networkInterface, accessConfig, options); + } + + /** + * Attaches a persistent disk to this instance given its configuration. + * + * @return a zone operation if the attach request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + public Operation attachDisk(PersistentDiskConfiguration configuration, + OperationOption... options) { + return compute.attachDisk(instanceId(), configuration, options); + } + + /** + * Attaches a persistent disk to this instance given the device name and its configuration. + * + * @return a zone operation if the attach request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + public Operation attachDisk(String deviceName, PersistentDiskConfiguration configuration, + OperationOption... options) { + return compute.attachDisk(instanceId(), deviceName, configuration, options); + } + + /** + * Attaches a persistent disk to this instance given the device name, its configuration and the + * device index. + * + * @return a zone operation if the attach request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + public Operation attachDisk(String deviceName, PersistentDiskConfiguration configuration, + int index, OperationOption... options) { + return compute.attachDisk(instanceId(), deviceName, configuration, index, options); + } + + /** + * Deletes an access configuration from the provided network interface for this instance. + * + * @return a zone operation if the delete request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + public Operation deleteAccessConfig(String networkInterface, String accessConfig, + OperationOption... options) { + return compute.deleteAccessConfig(instanceId(), networkInterface, accessConfig, options); + } + + /** + * Detaches a disk from this instance. + * + * @return a zone operation if the detach request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + public Operation detachDisk(String deviceName, OperationOption... options) { + return compute.detachDisk(instanceId(), deviceName, options); + } + + /** + * Returns the serial port output for this instance and port number. {@code port} must be between + * 1 and 4 (inclusive). + * + * @return the serial port output or {@code null} if the instance was not found + * @throws ComputeException upon failure + */ + public String getSerialPortOutput(int port) { + return compute.getSerialPortOutput(instanceId(), port); + } + + /** + * Returns the default serial port output for this instance. Default serial port corresponds to + * port number 1. + * + * @return the serial port output or {@code null} if the instance was not found + * @throws ComputeException upon failure + */ + public String getSerialPortOutput() { + return compute.getSerialPortOutput(instanceId()); + } + + /** + * Resets this instance. + * + * @return a zone operation if the reset request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + public Operation reset(OperationOption... options) { + return compute.reset(instanceId(), options); + } + + /** + * Sets the auto-delete flag for a disk attached to this instance. + * + * @return a zone operation if the flag setting request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + public Operation setDiskAutoDelete(String deviceName, boolean autoDelete, + OperationOption... options) { + return compute.setDiskAutoDelete(instanceId(), deviceName, autoDelete, options); + } + + /** + * Sets the machine type for this instance. The instance must be in + * {@link InstanceInfo.Status#TERMINATED} state to be able to set its machine type. + * + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + public Operation setMachineType(MachineTypeId machineType, OperationOption... options) { + return compute.setMachineType(instanceId(), machineType, options); + } + + /** + * Sets the metadata for this instance. + * + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + public Operation setMetadata(Metadata metadata, OperationOption... options) { + return compute.setMetadata(instanceId(), metadata, options); + } + + /** + * Sets the metadata for this instance, fingerprint value is taken from this instance's + * {@code tags().fingerprint()}. + * + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + public Operation setMetadata(Map metadata, OperationOption... options) { + return setMetadata(metadata().toBuilder().values(metadata).build(), options); + } + + /** + * Sets the scheduling options for this instance. + * + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + public Operation setSchedulingOptions(SchedulingOptions scheduling, OperationOption... options) { + return compute.setSchedulingOptions(instanceId(), scheduling, options); + } + + /** + * Sets the tags for this instance. + * + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + public Operation setTags(Tags tags, OperationOption... options) { + return compute.setTags(instanceId(), tags, options); + } + + /** + * Sets the tags for this instance, fingerprint value is taken from this instance's + * {@code tags().fingerprint()}. + * + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + public Operation setTags(Iterable tags, OperationOption... options) { + return setTags(tags().toBuilder().values(tags).build(), options); + } + + /** + * Starts this instance. + * + * @return a zone operation if the start request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + public Operation start(OperationOption... options) { + return compute.start(instanceId(), options); + } + + /** + * Stops this instance. + * + * @return a zone operation if the stop request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + public Operation stop(OperationOption... options) { + return compute.stop(instanceId(), options); + } + + /** + * Returns the snapshot'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(Instance.class)) { + return false; + } + Instance other = (Instance) 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 Instance fromPb(Compute compute, + com.google.api.services.compute.model.Instance instancePb) { + return new Instance(compute, new InstanceInfo.BuilderImpl(instancePb)); + } +} 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 f3e51266aa50..4da5931d064c 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 @@ -16,18 +16,24 @@ package com.google.gcloud.compute.spi; +import com.google.api.services.compute.model.AccessConfig; import com.google.api.services.compute.model.Address; +import com.google.api.services.compute.model.AttachedDisk; import com.google.api.services.compute.model.DeprecationStatus; import com.google.api.services.compute.model.Disk; import com.google.api.services.compute.model.DiskType; import com.google.api.services.compute.model.Image; +import com.google.api.services.compute.model.Instance; import com.google.api.services.compute.model.License; import com.google.api.services.compute.model.MachineType; +import com.google.api.services.compute.model.Metadata; 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.Scheduling; import com.google.api.services.compute.model.Snapshot; import com.google.api.services.compute.model.Subnetwork; +import com.google.api.services.compute.model.Tags; import com.google.api.services.compute.model.Zone; import com.google.gcloud.compute.ComputeException; @@ -496,4 +502,171 @@ Operation deprecateImage(String project, String image, DeprecationStatus depreca * @throws ComputeException upon failure */ Operation deleteNetwork(String network, Map options); + + /** + * Creates a new instance. + * + * @return a zone operation for instance's creation + * @throws ComputeException upon failure or if the zone does not exist + */ + Operation createInstance(String zone, Instance instance, Map options); + + /** + * Returns the requested instance or {@code null} if not found. + * + * @throws ComputeException upon failure or if the zone does not exist + */ + Instance getInstance(String zone, String instance, Map options); + + /** + * Lists instances for the provided zone. + * + * @throws ComputeException upon failure or if the zone does not exist + */ + Tuple> listInstances(String zone, Map options); + + /** + * Lists instances. + * + * @throws ComputeException upon failure + */ + Tuple> listInstances(Map options); + + /** + * Deletes the requested instance. + * + * @return a zone operation if the delete request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure or if the zone does not exist + */ + Operation deleteInstance(String zone, String instance, Map options); + + /** + * Adds an access configuration to an instance's network interface. + * + * @return a zone operation if the add request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + Operation addAccessConfig(String zone, String instance, String networkInterface, + AccessConfig accessConfig, Map options); + + /** + * Attaches a disk to an instance. + * + * @return a zone operation if the attach request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation attachDisk(String zone, String instance, AttachedDisk attachedDisk, + Map options); + + /** + * Deletes an access configuration from an instance's network interface. + * + * @return a zone operation if the delete request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation deleteAccessConfig(String zone, String instance, String networkInterface, + String accessConfig, Map options); + + /** + * Detaches a disk from an instance. + * + * @return a zone operation if the detach request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation detachDisk(String zone, String instance, String deviceName, Map options); + + /** + * Returns the serial port output for the provided instance and port number. {@code port} must be + * between 1 and 4 (inclusive). If {@code port} is {@code null} output for the default port (1) is + * returned. + * + * @return the serial port output or {@code null} if the instance was not found + * @throws ComputeException upon failure + */ + String getSerialPortOutput(String zone, String instance, Integer port, Map options); + + /** + * Resets the provided instance. + * + * @return a zone operation if the reset request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation reset(String zone, String instance, Map options); + + /** + * Sets the auto-delete flag for a disk attached to the provided instance. + * + * @return a zone operation if the flag setting request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation setDiskAutoDelete(String zone, String instance, String deviceName, boolean autoDelete, + Map options); + + /** + * Sets the machine type for the provided instance. Instance must be in {@code TERMINATED} state + * to be able to set its machine type. + * + * @param zone name of the zone in which the instance resides + * @param instance name of the instance + * @param machineTypeUrl full or partial URL of the machine type resource. For example + * {@code zones/us-central1-f/machineTypes/n1-standard-1}. + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + Operation setMachineType(String zone, String instance, String machineTypeUrl, + Map options); + + /** + * Sets the metadata for the provided instance. + * + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + Operation setMetadata(String zone, String instance, Metadata metadata, Map options); + + /** + * Sets the scheduling options for the provided instance. + * + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + Operation setScheduling(String zone, String instance, Scheduling scheduling, + Map options); + + /** + * Sets the tags for the provided instance. + * + * @return a zone operation if the set request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + Operation setTags(String zone, String instance, Tags tags, Map options); + + /** + * Starts the provided instance. + * + * @return a zone operation if the start request was issued correctly, {@code null} if the + * instance was not found + * @throws ComputeException upon failure + */ + Operation start(String zone, String instance, Map options); + + /** + * Stops the provided instance. + * + * @return a zone operation if the stop request was issued correctly, {@code null} if the instance + * was not found + * @throws ComputeException upon failure + */ + Operation stop(String zone, String instance, 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 9db50af5db4c..48f9f8d187d5 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 @@ -26,10 +26,12 @@ import com.google.api.client.http.HttpTransport; import com.google.api.client.json.jackson.JacksonFactory; import com.google.api.services.compute.Compute; +import com.google.api.services.compute.model.AccessConfig; import com.google.api.services.compute.model.Address; import com.google.api.services.compute.model.AddressAggregatedList; import com.google.api.services.compute.model.AddressList; import com.google.api.services.compute.model.AddressesScopedList; +import com.google.api.services.compute.model.AttachedDisk; import com.google.api.services.compute.model.DeprecationStatus; import com.google.api.services.compute.model.Disk; import com.google.api.services.compute.model.DiskAggregatedList; @@ -42,23 +44,32 @@ import com.google.api.services.compute.model.DisksScopedList; import com.google.api.services.compute.model.Image; import com.google.api.services.compute.model.ImageList; +import com.google.api.services.compute.model.Instance; +import com.google.api.services.compute.model.InstanceAggregatedList; +import com.google.api.services.compute.model.InstanceList; +import com.google.api.services.compute.model.InstancesScopedList; +import com.google.api.services.compute.model.InstancesSetMachineTypeRequest; import com.google.api.services.compute.model.License; import com.google.api.services.compute.model.MachineType; 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.Metadata; 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.Scheduling; +import com.google.api.services.compute.model.SerialPortOutput; 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.Tags; import com.google.api.services.compute.model.Zone; import com.google.api.services.compute.model.ZoneList; import com.google.common.collect.ImmutableList; @@ -869,6 +880,256 @@ public Operation deleteNetwork(String network, Map options) { } } + @Override + public Operation createInstance(String zone, Instance instance, Map options) { + try { + return compute.instances() + .insert(this.options.projectId(), zone, instance) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Instance getInstance(String zone, String instance, Map options) { + try { + return compute.instances() + .get(this.options.projectId(), zone, instance) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Tuple> listInstances(String zone, Map options) { + try { + InstanceList instanceList = compute.instances() + .list(this.options.projectId(), zone) + .setFilter(FILTER.getString(options)) + .setMaxResults(MAX_RESULTS.getLong(options)) + .setPageToken(PAGE_TOKEN.getString(options)) + .setFields(FIELDS.getString(options)) + .execute(); + Iterable instances = instanceList.getItems(); + return Tuple.of(instanceList.getNextPageToken(), instances); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Tuple> listInstances(Map options) { + try { + InstanceAggregatedList aggregatedList = compute.instances() + .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 (InstancesScopedList instancesScopedList : scopedList.values()) { + if (instancesScopedList.getInstances() != null) { + builder.addAll(instancesScopedList.getInstances()); + } + } + } + return Tuple.>of(aggregatedList.getNextPageToken(), + builder.build()); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Operation deleteInstance(String zone, String instance, Map options) { + try { + return compute.instances() + .delete(this.options.projectId(), zone, instance) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Operation addAccessConfig(String zone, String instance, String networkInterface, + AccessConfig accessConfig, Map options) { + try { + return compute.instances() + .addAccessConfig(this.options.projectId(), zone, instance, networkInterface, accessConfig) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Operation attachDisk(String zone, String instance, AttachedDisk attachedDisk, + Map options) { + try { + return compute.instances() + .attachDisk(this.options.projectId(), zone, instance, attachedDisk) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Operation deleteAccessConfig(String zone, String instance, String networkInterface, + String accessConfig, Map options) { + try { + return compute.instances() + .deleteAccessConfig(this.options.projectId(), zone, instance, accessConfig, + networkInterface) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Operation detachDisk(String zone, String instance, String deviceName, + Map options) { + try { + return compute.instances() + .detachDisk(this.options.projectId(), zone, instance, deviceName) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public String getSerialPortOutput(String zone, String instance, Integer port, + Map options) { + try { + SerialPortOutput portOutput = compute.instances() + .getSerialPortOutput(this.options.projectId(), zone, instance) + .setPort(port) + .setFields(FIELDS.getString(options)) + .execute(); + return portOutput != null ? portOutput.getContents() : null; + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Operation reset(String zone, String instance, Map options) { + try { + return compute.instances() + .reset(this.options.projectId(), zone, instance) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Operation setDiskAutoDelete(String zone, String instance, String deviceName, + boolean autoDelete, Map options) { + try { + return compute.instances() + .setDiskAutoDelete(this.options.projectId(), zone, instance, autoDelete, deviceName) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Operation setMachineType(String zone, String instance, String machineTypeUrl, + Map options) { + try { + InstancesSetMachineTypeRequest request = + new InstancesSetMachineTypeRequest().setMachineType(machineTypeUrl); + return compute.instances() + .setMachineType(this.options.projectId(), zone, instance, request) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Operation setMetadata(String zone, String instance, Metadata metadata, + Map options) { + try { + return compute.instances() + .setMetadata(this.options.projectId(), zone, instance, metadata) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Operation setScheduling(String zone, String instance, Scheduling scheduling, + Map options) { + try { + return compute.instances() + .setScheduling(this.options.projectId(), zone, instance, scheduling) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Operation setTags(String zone, String instance, Tags tags, Map options) { + try { + return compute.instances() + .setTags(this.options.projectId(), zone, instance, tags) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Operation start(String zone, String instance, Map options) { + try { + return compute.instances() + .start(this.options.projectId(), zone, instance) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Operation stop(String zone, String instance, Map options) { + try { + return compute.instances() + .stop(this.options.projectId(), zone, instance) + .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 3dd28c043fd7..023bd7064a3e 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 @@ -34,6 +34,7 @@ import com.google.common.collect.Iterables; import com.google.gcloud.Page; import com.google.gcloud.RetryParams; +import com.google.gcloud.compute.AttachedDisk.PersistentDiskConfiguration; import com.google.gcloud.compute.Compute.AddressAggregatedListOption; import com.google.gcloud.compute.Compute.AddressFilter; import com.google.gcloud.compute.Compute.AddressListOption; @@ -51,6 +52,11 @@ import com.google.gcloud.compute.Compute.ImageFilter; import com.google.gcloud.compute.Compute.ImageListOption; import com.google.gcloud.compute.Compute.ImageOption; +import com.google.gcloud.compute.Compute.InstanceAggregatedListOption; +import com.google.gcloud.compute.Compute.InstanceField; +import com.google.gcloud.compute.Compute.InstanceFilter; +import com.google.gcloud.compute.Compute.InstanceListOption; +import com.google.gcloud.compute.Compute.InstanceOption; import com.google.gcloud.compute.Compute.LicenseOption; import com.google.gcloud.compute.Compute.MachineTypeAggregatedListOption; import com.google.gcloud.compute.Compute.MachineTypeFilter; @@ -77,6 +83,7 @@ import com.google.gcloud.compute.Compute.ZoneFilter; import com.google.gcloud.compute.Compute.ZoneListOption; import com.google.gcloud.compute.Compute.ZoneOption; +import com.google.gcloud.compute.NetworkInterface.AccessConfig; import com.google.gcloud.compute.Operation.OperationError; import com.google.gcloud.compute.Operation.OperationWarning; import com.google.gcloud.compute.Operation.Status; @@ -213,6 +220,14 @@ public class ComputeImplTest { 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")); + private static final InstanceId INSTANCE_ID = InstanceId.of("project", "zone", "instance"); + private static final PersistentDiskConfiguration PERSISTENT_DISK_CONFIGURATION = + PersistentDiskConfiguration.of(DISK_ID); + private static final AttachedDisk ATTACHED_DISK = + AttachedDisk.of("device", PERSISTENT_DISK_CONFIGURATION); + private static final NetworkInterface NETWORK_INTERFACE = NetworkInterface.of(NETWORK_ID); + private static final InstanceInfo INSTANCE = + InstanceInfo.of(INSTANCE_ID, MACHINE_TYPE_ID, ATTACHED_DISK, NETWORK_INTERFACE); // Empty ComputeRpc options private static final Map EMPTY_RPC_OPTIONS = ImmutableMap.of(); @@ -450,6 +465,32 @@ public class ComputeImplTest { MAX_RESULTS, 42L, FILTER, "IPv4Range eq 192.168.0.0/16"); + // Instance options + private static final InstanceOption INSTANCE_OPTION_FIELDS = + InstanceOption.fields(InstanceField.ID, InstanceField.DESCRIPTION); + + // Instance list options + private static final InstanceFilter INSTANCE_FILTER = + InstanceFilter.equals(InstanceField.CAN_IP_FORWARD, true); + private static final InstanceListOption INSTANCE_LIST_PAGE_TOKEN = + InstanceListOption.pageToken("cursor"); + private static final InstanceListOption INSTANCE_LIST_PAGE_SIZE = + InstanceListOption.pageSize(42L); + private static final InstanceListOption INSTANCE_LIST_FILTER = + InstanceListOption.filter(INSTANCE_FILTER); + private static final Map INSTANCE_LIST_OPTIONS = ImmutableMap.of( + PAGE_TOKEN, "cursor", + MAX_RESULTS, 42L, + FILTER, "canIpForward eq true"); + + // Instance aggregated list options + private static final InstanceAggregatedListOption INSTANCE_AGGREGATED_LIST_PAGE_TOKEN = + InstanceAggregatedListOption.pageToken("cursor"); + private static final InstanceAggregatedListOption INSTANCE_AGGREGATED_LIST_PAGE_SIZE = + InstanceAggregatedListOption.pageSize(42L); + private static final InstanceAggregatedListOption INSTANCE_AGGREGATED_LIST_FILTER = + InstanceAggregatedListOption.filter(INSTANCE_FILTER); + private static final Function OPERATION_TO_PB_FUNCTION = new Function() { @@ -3166,6 +3207,781 @@ public void testCreateNetworkWithOptions() { assertEquals(globalOperation, operation); } + @Test + public void testGetInstance() { + EasyMock.expect(computeRpcMock.getInstance(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + EMPTY_RPC_OPTIONS)).andReturn(INSTANCE.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Instance instance = compute.get(INSTANCE_ID); + assertEquals(new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE)), instance); + } + + @Test + public void testGetInstance_Null() { + EasyMock.expect(computeRpcMock.getInstance(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.get(INSTANCE_ID)); + } + + @Test + public void testGetInstanceWithSelectedFields() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.getInstance(eq(INSTANCE_ID.zone()), eq(INSTANCE_ID.instance()), + capture(capturedOptions))).andReturn(INSTANCE.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Instance instance = compute.get(INSTANCE_ID, INSTANCE_OPTION_FIELDS); + String selector = (String) capturedOptions.getValue().get(INSTANCE_OPTION_FIELDS.rpcOption()); + assertTrue(selector.contains("selfLink")); + assertTrue(selector.contains("id")); + assertTrue(selector.contains("description")); + assertEquals(23, selector.length()); + assertEquals(new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE)), instance); + } + + @Test + public void testDeleteInstance_Operation() { + EasyMock.expect(computeRpcMock.deleteInstance(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, compute.delete(INSTANCE_ID)); + } + + @Test + public void testDeleteInstanceWithSelectedFields_Operation() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.deleteInstance(eq(INSTANCE_ID.zone()), + eq(INSTANCE_ID.instance()), capture(capturedOptions))).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.delete(INSTANCE_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(zoneOperation, operation); + } + + @Test + public void testDeleteInstance_Null() { + EasyMock.expect(computeRpcMock.deleteInstance(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.delete(INSTANCE_ID)); + } + + @Test + public void testListInstances() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList instanceList = ImmutableList.of( + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE)), + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(instanceList, InstanceInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listInstances(INSTANCE_ID.zone(), EMPTY_RPC_OPTIONS)) + .andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listInstances(INSTANCE_ID.zone()); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(instanceList.toArray(), Iterables.toArray(page.values(), Instance.class)); + } + + @Test + public void testListInstancesNextPage() { + String cursor = "cursor"; + String nextCursor = "nextCursor"; + compute = options.service(); + ImmutableList instanceList = ImmutableList.of( + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE)), + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE))); + ImmutableList nextInstanceList = ImmutableList.of( + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(instanceList, InstanceInfo.TO_PB_FUNCTION)); + Tuple> nextResult = + Tuple.of(nextCursor, Iterables.transform(nextInstanceList, InstanceInfo.TO_PB_FUNCTION)); + Map nextOptions = ImmutableMap.of(PAGE_TOKEN, cursor); + EasyMock.expect(computeRpcMock.listInstances(INSTANCE_ID.zone(), EMPTY_RPC_OPTIONS)) + .andReturn(result); + EasyMock.expect(computeRpcMock.listInstances(INSTANCE_ID.zone(), nextOptions)) + .andReturn(nextResult); + EasyMock.replay(computeRpcMock); + Page page = compute.listInstances(INSTANCE_ID.zone()); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(instanceList.toArray(), Iterables.toArray(page.values(), Instance.class)); + page = page.nextPage(); + assertEquals(nextCursor, page.nextPageCursor()); + assertArrayEquals(nextInstanceList.toArray(), Iterables.toArray(page.values(), Instance.class)); + } + + @Test + public void testListEmptyInstances() { + compute = options.service(); + ImmutableList instances = ImmutableList.of(); + Tuple> result = + Tuple.>of(null, instances); + EasyMock.expect(computeRpcMock.listInstances(INSTANCE_ID.zone(), EMPTY_RPC_OPTIONS)) + .andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listInstances(INSTANCE_ID.zone()); + assertNull(page.nextPageCursor()); + assertArrayEquals(instances.toArray(), Iterables.toArray(page.values(), Instance.class)); + } + + @Test + public void testListInstancesWithOptions() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList instanceList = ImmutableList.of( + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE)), + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(instanceList, InstanceInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listInstances(INSTANCE_ID.zone(), INSTANCE_LIST_OPTIONS)) + .andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listInstances(INSTANCE_ID.zone(), INSTANCE_LIST_PAGE_SIZE, + INSTANCE_LIST_PAGE_TOKEN, INSTANCE_LIST_FILTER); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(instanceList.toArray(), Iterables.toArray(page.values(), Instance.class)); + } + + @Test + public void testAggregatedListInstances() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList instanceList = ImmutableList.of( + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE)), + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(instanceList, InstanceInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listInstances(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listInstances(); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(instanceList.toArray(), Iterables.toArray(page.values(), Instance.class)); + } + + @Test + public void testAggregatedListInstancesNextPage() { + String cursor = "cursor"; + String nextCursor = "nextCursor"; + compute = options.service(); + ImmutableList instanceList = ImmutableList.of( + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE)), + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE))); + ImmutableList nextInstanceList = ImmutableList.of( + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(instanceList, InstanceInfo.TO_PB_FUNCTION)); + Tuple> nextResult = + Tuple.of(nextCursor, Iterables.transform(nextInstanceList, InstanceInfo.TO_PB_FUNCTION)); + Map nextOptions = ImmutableMap.of(PAGE_TOKEN, cursor); + EasyMock.expect(computeRpcMock.listInstances(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.expect(computeRpcMock.listInstances(nextOptions)).andReturn(nextResult); + EasyMock.replay(computeRpcMock); + Page page = compute.listInstances(); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(instanceList.toArray(), Iterables.toArray(page.values(), Instance.class)); + page = page.nextPage(); + assertEquals(nextCursor, page.nextPageCursor()); + assertArrayEquals(nextInstanceList.toArray(), Iterables.toArray(page.values(), Instance.class)); + } + + @Test + public void testAggregatedListEmptyInstances() { + compute = options.service(); + ImmutableList instanceList = ImmutableList.of(); + Tuple> result = + Tuple.>of(null, + instanceList); + EasyMock.expect(computeRpcMock.listInstances(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listInstances(); + assertNull(page.nextPageCursor()); + assertArrayEquals(instanceList.toArray(), Iterables.toArray(page.values(), Instance.class)); + } + + @Test + public void testAggregatedListInstancesWithOptions() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList instanceList = ImmutableList.of( + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE)), + new Instance(compute, new InstanceInfo.BuilderImpl(INSTANCE))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(instanceList, InstanceInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listInstances(INSTANCE_LIST_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + Page page = compute.listInstances(INSTANCE_AGGREGATED_LIST_PAGE_SIZE, + INSTANCE_AGGREGATED_LIST_PAGE_TOKEN, INSTANCE_AGGREGATED_LIST_FILTER); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(instanceList.toArray(), Iterables.toArray(page.values(), Instance.class)); + } + + @Test + public void testCreateInstance() { + EasyMock.expect(computeRpcMock.createInstance(INSTANCE_ID.zone(), INSTANCE.toPb(), + EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + InstanceInfo instance = InstanceInfo.of(InstanceId.of("zone", "instance"), + MachineTypeId.of("zone", "type"), ATTACHED_DISK, + NetworkInterface.of(NetworkId.of("network"))); + Operation operation = compute.create(instance); + assertEquals(zoneOperation, operation); + } + + @Test + public void testCreateInstanceWithOptions() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.createInstance(eq(INSTANCE_ID.zone()), eq(INSTANCE.toPb()), + capture(capturedOptions))).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.create(INSTANCE, 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(zoneOperation, operation); + } + + @Test + public void testAddAccessConfig_Operation() { + AccessConfig accessConfig = AccessConfig.of("192.168.1.1"); + EasyMock.expect(computeRpcMock.addAccessConfig(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + "networkInterface", accessConfig.toPb(), EMPTY_RPC_OPTIONS)) + .andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, + compute.addAccessConfig(INSTANCE_ID, "networkInterface", accessConfig)); + } + + @Test + public void testAddAccessConfigWithSelectedFields_Operation() { + Capture> capturedOptions = Capture.newInstance(); + AccessConfig accessConfig = AccessConfig.of("192.168.1.1"); + EasyMock.expect(computeRpcMock.addAccessConfig(eq(INSTANCE_ID.zone()), + eq(INSTANCE_ID.instance()), eq("networkInterface"), eq(accessConfig.toPb()), + capture(capturedOptions))).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.addAccessConfig(INSTANCE_ID, "networkInterface", accessConfig, + 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(zoneOperation, operation); + } + + @Test + public void testAddAccessConfig_Null() { + AccessConfig accessConfig = AccessConfig.of("192.168.1.1"); + EasyMock.expect(computeRpcMock.addAccessConfig(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + "networkInterface", accessConfig.toPb(), EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.addAccessConfig(INSTANCE_ID, "networkInterface", accessConfig)); + } + + @Test + public void testAttachDisk_Operation() { + AttachedDisk attachedDisk = AttachedDisk.of(PERSISTENT_DISK_CONFIGURATION); + EasyMock.expect(computeRpcMock.attachDisk(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + attachedDisk.toPb(), EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, compute.attachDisk(INSTANCE_ID, PERSISTENT_DISK_CONFIGURATION)); + } + + @Test + public void testAttachDiskWithSelectedFields_Operation() { + AttachedDisk attachedDisk = AttachedDisk.of(PERSISTENT_DISK_CONFIGURATION); + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.attachDisk(eq(INSTANCE_ID.zone()), eq(INSTANCE_ID.instance()), + eq(attachedDisk.toPb()), capture(capturedOptions))).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = + compute.attachDisk(INSTANCE_ID, PERSISTENT_DISK_CONFIGURATION, 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(zoneOperation, operation); + } + + @Test + public void testAttachDisk_Null() { + AttachedDisk attachedDisk = AttachedDisk.of(PERSISTENT_DISK_CONFIGURATION); + EasyMock.expect(computeRpcMock.attachDisk(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + attachedDisk.toPb(), EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.attachDisk(INSTANCE_ID, PERSISTENT_DISK_CONFIGURATION)); + } + + @Test + public void testAttachDiskName_Operation() { + AttachedDisk attachedDisk = AttachedDisk.of("dev0", PERSISTENT_DISK_CONFIGURATION); + EasyMock.expect(computeRpcMock.attachDisk(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + attachedDisk.toPb(), EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, + compute.attachDisk(INSTANCE_ID, "dev0", PERSISTENT_DISK_CONFIGURATION)); + } + + @Test + public void testAttachDiskNameWithSelectedFields_Operation() { + AttachedDisk attachedDisk = AttachedDisk.of("dev0", PERSISTENT_DISK_CONFIGURATION); + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.attachDisk(eq(INSTANCE_ID.zone()), eq(INSTANCE_ID.instance()), + eq(attachedDisk.toPb()), capture(capturedOptions))).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.attachDisk(INSTANCE_ID, "dev0", PERSISTENT_DISK_CONFIGURATION, + 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(zoneOperation, operation); + } + + @Test + public void testAttachDiskName_Null() { + AttachedDisk attachedDisk = AttachedDisk.of("dev0", PERSISTENT_DISK_CONFIGURATION); + EasyMock.expect(computeRpcMock.attachDisk(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + attachedDisk.toPb(), EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.attachDisk(INSTANCE_ID, "dev0", PERSISTENT_DISK_CONFIGURATION)); + } + + @Test + public void testDeleteAccessConfig_Operation() { + EasyMock.expect(computeRpcMock.deleteAccessConfig(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + "networkInterface", "accessConfig", EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, + compute.deleteAccessConfig(INSTANCE_ID, "networkInterface", "accessConfig")); + } + + @Test + public void testDeleteAccessConfigWithSelectedFields_Operation() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.deleteAccessConfig(eq(INSTANCE_ID.zone()), + eq(INSTANCE_ID.instance()), eq("networkInterface"), eq("accessConfig"), + capture(capturedOptions))).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.deleteAccessConfig(INSTANCE_ID, "networkInterface", + "accessConfig", 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(zoneOperation, operation); + } + + @Test + public void testDeleteAccessConfig_Null() { + EasyMock.expect(computeRpcMock.deleteAccessConfig(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + "networkInterface", "accessConfig", EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.deleteAccessConfig(INSTANCE_ID, "networkInterface", "accessConfig")); + } + + @Test + public void testDetachDisk_Operation() { + EasyMock.expect(computeRpcMock.detachDisk(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + "device", EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, compute.detachDisk(INSTANCE_ID, "device")); + } + + @Test + public void testDetachDiskWithSelectedFields_Operation() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.detachDisk(eq(INSTANCE_ID.zone()), + eq(INSTANCE_ID.instance()), eq("device"), capture(capturedOptions))) + .andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.detachDisk(INSTANCE_ID, "device", 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(zoneOperation, operation); + } + + @Test + public void testDetachDisk_Null() { + EasyMock.expect(computeRpcMock.detachDisk(INSTANCE_ID.zone(), INSTANCE_ID.instance(), "device", + EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.detachDisk(INSTANCE_ID, "device")); + } + + @Test + public void testSerialPortOutputFromPort() { + String output = "output"; + EasyMock.expect(computeRpcMock.getSerialPortOutput(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + 2, EMPTY_RPC_OPTIONS)).andReturn(output); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(output, compute.getSerialPortOutput(INSTANCE_ID, 2)); + } + + @Test + public void testSerialPortOutputDefault() { + String output = "output"; + EasyMock.expect(computeRpcMock.getSerialPortOutput(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + null, EMPTY_RPC_OPTIONS)).andReturn(output); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(output, compute.getSerialPortOutput(INSTANCE_ID)); + } + + @Test + public void testSerialPortOutputFromPort_Null() { + EasyMock.expect(computeRpcMock.getSerialPortOutput(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + 2, EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.getSerialPortOutput(INSTANCE_ID, 2)); + } + + @Test + public void testSerialPortOutputDefault_Null() { + EasyMock.expect(computeRpcMock.getSerialPortOutput(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + null, EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.getSerialPortOutput(INSTANCE_ID)); + } + + @Test + public void testResetInstance_Operation() { + EasyMock.expect(computeRpcMock.reset(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, compute.reset(INSTANCE_ID)); + } + + @Test + public void testResetInstanceWithSelectedFields_Operation() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.reset(eq(INSTANCE_ID.zone()), eq(INSTANCE_ID.instance()), + capture(capturedOptions))).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.reset(INSTANCE_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(zoneOperation, operation); + } + + @Test + public void testResetInstance_Null() { + EasyMock.expect(computeRpcMock.reset(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.reset(INSTANCE_ID)); + } + + @Test + public void testSetDiskAutodelete_Operation() { + EasyMock.expect(computeRpcMock.setDiskAutoDelete(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + "device", true, EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, compute.setDiskAutoDelete(INSTANCE_ID, "device", true)); + } + + @Test + public void testSetDiskAutodeleteWithSelectedFields_Operation() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.setDiskAutoDelete(eq(INSTANCE_ID.zone()), + eq(INSTANCE_ID.instance()), eq("device"), eq(true), capture(capturedOptions))) + .andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = + compute.setDiskAutoDelete(INSTANCE_ID, "device", true, 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(zoneOperation, operation); + } + + @Test + public void testSetDiskAutodelete_Null() { + EasyMock.expect(computeRpcMock.setDiskAutoDelete(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + "device", false, EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.setDiskAutoDelete(INSTANCE_ID, "device", false)); + } + + @Test + public void testSetMachineType_Operation() { + EasyMock.expect(computeRpcMock.setMachineType(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + MACHINE_TYPE_ID.selfLink(), EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, + compute.setMachineType(INSTANCE_ID, MachineTypeId.of("zone", "type"))); + } + + @Test + public void testSetMachineTypeWithOptions_Operation() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.setMachineType(eq(INSTANCE_ID.zone()), + eq(INSTANCE_ID.instance()), eq(MACHINE_TYPE_ID.selfLink()), capture(capturedOptions))) + .andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.setMachineType(INSTANCE_ID, MachineTypeId.of("zone", "type"), + 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(zoneOperation, operation); + } + + @Test + public void testSetMachineType_Null() { + EasyMock.expect(computeRpcMock.setMachineType(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + MACHINE_TYPE_ID.selfLink(), EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.setMachineType(INSTANCE_ID, MachineTypeId.of("zone", "type"))); + } + + @Test + public void testSetMetadata_Operation() { + Metadata metadata = Metadata.builder() + .add("key", "value") + .fingerprint("fingerprint") + .build(); + EasyMock.expect(computeRpcMock.setMetadata(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + metadata.toPb(), EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, compute.setMetadata(INSTANCE_ID, metadata)); + } + + @Test + public void testSetMetadataWithOptions_Operation() { + Capture> capturedOptions = Capture.newInstance(); + Metadata metadata = Metadata.builder() + .add("key", "value") + .fingerprint("fingerprint") + .build(); + EasyMock.expect(computeRpcMock.setMetadata(eq(INSTANCE_ID.zone()), eq(INSTANCE_ID.instance()), + eq(metadata.toPb()), capture(capturedOptions))).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.setMetadata(INSTANCE_ID, metadata, 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(zoneOperation, operation); + } + + @Test + public void testSetMetadata_Null() { + Metadata metadata = Metadata.builder() + .add("key", "value") + .fingerprint("fingerprint") + .build(); + EasyMock.expect(computeRpcMock.setMetadata(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + metadata.toPb(), EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.setMetadata(INSTANCE_ID, metadata)); + } + + @Test + public void testSetSchedulingOptions_Operation() { + SchedulingOptions schedulingOptions = + SchedulingOptions.standard(true, SchedulingOptions.Maintenance.MIGRATE); + EasyMock.expect(computeRpcMock.setScheduling(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + schedulingOptions.toPb(), EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, compute.setSchedulingOptions(INSTANCE_ID, schedulingOptions)); + } + + @Test + public void testSetSchedulingOptionsWithOptions_Operation() { + Capture> capturedOptions = Capture.newInstance(); + SchedulingOptions schedulingOptions = + SchedulingOptions.standard(true, SchedulingOptions.Maintenance.MIGRATE); + EasyMock.expect(computeRpcMock.setScheduling(eq(INSTANCE_ID.zone()), eq(INSTANCE_ID.instance()), + eq(schedulingOptions.toPb()), capture(capturedOptions))).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = + compute.setSchedulingOptions(INSTANCE_ID, schedulingOptions, 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(zoneOperation, operation); + } + + @Test + public void testSetSchedulingOptions_Null() { + SchedulingOptions schedulingOptions = + SchedulingOptions.standard(true, SchedulingOptions.Maintenance.MIGRATE); + EasyMock.expect(computeRpcMock.setScheduling(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + schedulingOptions.toPb(), EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.setSchedulingOptions(INSTANCE_ID, schedulingOptions)); + } + + @Test + public void testTags_Operation() { + Tags tags = Tags.of("tag1", "tag2"); + EasyMock.expect(computeRpcMock.setTags(INSTANCE_ID.zone(), INSTANCE_ID.instance(), tags.toPb(), + EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, compute.setTags(INSTANCE_ID, tags)); + } + + @Test + public void testSetTagsWithOptions_Operation() { + Tags tags = Tags.of("tag1", "tag2"); + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.setTags(eq(INSTANCE_ID.zone()), eq(INSTANCE_ID.instance()), + eq(tags.toPb()), capture(capturedOptions))).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.setTags(INSTANCE_ID, tags, 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(zoneOperation, operation); + } + + @Test + public void testSetTags_Null() { + Tags tags = Tags.of("tag1", "tag2"); + EasyMock.expect(computeRpcMock.setTags(INSTANCE_ID.zone(), INSTANCE_ID.instance(), tags.toPb(), + EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.setTags(INSTANCE_ID, tags)); + } + + @Test + public void testStartInstance_Operation() { + EasyMock.expect(computeRpcMock.start(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, compute.start(INSTANCE_ID)); + } + + @Test + public void testStartInstanceWithSelectedFields_Operation() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.start(eq(INSTANCE_ID.zone()), eq(INSTANCE_ID.instance()), + capture(capturedOptions))).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.start(INSTANCE_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(zoneOperation, operation); + } + + @Test + public void testStartInstance_Null() { + EasyMock.expect(computeRpcMock.start(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.start(INSTANCE_ID)); + } + + @Test + public void testStopInstance_Operation() { + EasyMock.expect(computeRpcMock.stop(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(zoneOperation, compute.stop(INSTANCE_ID)); + } + + @Test + public void testStopInstanceWithSelectedFields_Operation() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.stop(eq(INSTANCE_ID.zone()), eq(INSTANCE_ID.instance()), + capture(capturedOptions))).andReturn(zoneOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.stop(INSTANCE_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(zoneOperation, operation); + } + + @Test + public void testStopInstance_Null() { + EasyMock.expect(computeRpcMock.stop(INSTANCE_ID.zone(), INSTANCE_ID.instance(), + EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.stop(INSTANCE_ID)); + } + @Test public void testRetryableException() { EasyMock.expect( diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/InstanceTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/InstanceTest.java new file mode 100644 index 000000000000..880ed68f63ab --- /dev/null +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/InstanceTest.java @@ -0,0 +1,895 @@ +/* + * 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 com.google.common.collect.ImmutableMap; +import com.google.gcloud.compute.AttachedDisk.PersistentDiskConfiguration; +import com.google.gcloud.compute.Compute.InstanceOption; +import com.google.gcloud.compute.Compute.OperationOption; +import com.google.gcloud.compute.NetworkInterface.AccessConfig; +import com.google.gcloud.compute.SchedulingOptions.Maintenance; + +import org.junit.Test; + +import java.util.List; +import java.util.Map; + +public class InstanceTest { + + private static final String ID = "42"; + private static final Long CREATION_TIMESTAMP = 1453293540000L; + private static final String DESCRIPTION = "description"; + private static final InstanceId INSTANCE_ID = InstanceId.of("project", "zone", "instance"); + private static final InstanceInfo.Status STATUS = InstanceInfo.Status.RUNNING; + private static final String STATUS_MESSAGE = "statusMessage"; + private static final Tags TAGS = Tags.builder() + .values("tag1", "tag2") + .fingerprint("fingerprint") + .build(); + private static final MachineTypeId MACHINE_TYPE = MachineTypeId.of("project", "zone", "type"); + private static final Boolean CAN_IP_FORWARD = true; + private static final NetworkInterface NETWORK_INTERFACE = + NetworkInterface.of(NetworkId.of("project", "network")); + private static final List NETWORK_INTERFACES = + ImmutableList.of(NETWORK_INTERFACE); + private static final DiskId DISK_ID = DiskId.of("project", "zone", "disk"); + private static final AttachedDisk ATTACHED_DISK = + AttachedDisk.of(PersistentDiskConfiguration.of(DISK_ID)); + private static final List ATTACHED_DISKS = ImmutableList.of(ATTACHED_DISK); + private static final Metadata METADATA = Metadata.builder() + .add("key1", "value1") + .add("key2", "value2") + .fingerprint("fingerprint") + .build(); + private static final ServiceAccount SERVICE_ACCOUNT = + ServiceAccount.of("email", ImmutableList.of("scope1")); + private static final List SERVICE_ACCOUNTS = + ImmutableList.of(SERVICE_ACCOUNT); + private static final SchedulingOptions SCHEDULING_OPTIONS = SchedulingOptions.preemptible(); + private static final String CPU_PLATFORM = "cpuPlatform"; + + private final Compute serviceMockReturnsOptions = createStrictMock(Compute.class); + private final ComputeOptions mockOptions = createMock(ComputeOptions.class); + private Compute compute; + private Instance instance; + private Instance expectedInstance; + + private void initializeExpectedInstance(int optionsCalls) { + expect(serviceMockReturnsOptions.options()).andReturn(mockOptions).times(optionsCalls); + replay(serviceMockReturnsOptions); + expectedInstance = new Instance.Builder(serviceMockReturnsOptions, INSTANCE_ID, MACHINE_TYPE, + ATTACHED_DISK, NETWORK_INTERFACE) + .id(ID) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .status(STATUS) + .statusMessage(STATUS_MESSAGE) + .tags(TAGS) + .canIpForward(CAN_IP_FORWARD) + .metadata(METADATA) + .serviceAccounts(SERVICE_ACCOUNTS) + .schedulingOptions(SCHEDULING_OPTIONS) + .cpuPlatform(CPU_PLATFORM) + .build(); + compute = createStrictMock(Compute.class); + } + + private void initializeInstance() { + instance = new Instance.Builder(compute, INSTANCE_ID, MACHINE_TYPE, + ATTACHED_DISK, NETWORK_INTERFACE) + .id(ID) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .status(STATUS) + .statusMessage(STATUS_MESSAGE) + .tags(TAGS) + .canIpForward(CAN_IP_FORWARD) + .metadata(METADATA) + .serviceAccounts(SERVICE_ACCOUNTS) + .schedulingOptions(SCHEDULING_OPTIONS) + .cpuPlatform(CPU_PLATFORM) + .build(); + } + + @Test + public void testToBuilder() { + initializeExpectedInstance(8); + compareInstance(expectedInstance, expectedInstance.toBuilder().build()); + Instance newInstance = expectedInstance.toBuilder().description("newDescription").build(); + assertEquals("newDescription", newInstance.description()); + newInstance = newInstance.toBuilder().description("description").build(); + compareInstance(expectedInstance, newInstance); + } + + @Test + public void testToBuilderIncomplete() { + initializeExpectedInstance(5); + InstanceInfo instanceInfo = + InstanceInfo.of(INSTANCE_ID, MACHINE_TYPE, ATTACHED_DISK, NETWORK_INTERFACE); + Instance instance = + new Instance(serviceMockReturnsOptions, new InstanceInfo.BuilderImpl(instanceInfo)); + compareInstance(instance, instance.toBuilder().build()); + } + + @Test + public void testBuilder() { + initializeExpectedInstance(2); + assertEquals(ID, expectedInstance.id()); + assertEquals(INSTANCE_ID, expectedInstance.instanceId()); + assertEquals(CREATION_TIMESTAMP, expectedInstance.creationTimestamp()); + assertEquals(DESCRIPTION, expectedInstance.description()); + assertEquals(STATUS, expectedInstance.status()); + assertEquals(STATUS_MESSAGE, expectedInstance.statusMessage()); + assertEquals(TAGS, expectedInstance.tags()); + assertEquals(MACHINE_TYPE, expectedInstance.machineType()); + assertEquals(CAN_IP_FORWARD, expectedInstance.canIpForward()); + assertEquals(NETWORK_INTERFACES, expectedInstance.networkInterfaces()); + assertEquals(ATTACHED_DISKS, expectedInstance.attachedDisks()); + assertEquals(METADATA, expectedInstance.metadata()); + assertEquals(SERVICE_ACCOUNTS, expectedInstance.serviceAccounts()); + assertEquals(SCHEDULING_OPTIONS, expectedInstance.schedulingOptions()); + assertEquals(CPU_PLATFORM, expectedInstance.cpuPlatform()); + assertSame(serviceMockReturnsOptions, expectedInstance.compute()); + InstanceInfo instanceInfo = + InstanceInfo.of(INSTANCE_ID, MACHINE_TYPE, ATTACHED_DISK, NETWORK_INTERFACE); + Instance instance = + new Instance(serviceMockReturnsOptions, new InstanceInfo.BuilderImpl(instanceInfo)); + assertNull(instance.id()); + assertEquals(INSTANCE_ID, instance.instanceId()); + assertNull(instance.creationTimestamp()); + assertNull(instance.description()); + assertNull(instance.status()); + assertNull(instance.statusMessage()); + assertNull(instance.tags()); + assertEquals(MACHINE_TYPE, instance.machineType()); + assertNull(instance.canIpForward()); + assertEquals(NETWORK_INTERFACES, instance.networkInterfaces()); + assertEquals(ATTACHED_DISKS, instance.attachedDisks()); + assertNull(instance.metadata()); + assertNull(instance.serviceAccounts()); + assertNull(instance.schedulingOptions()); + assertNull(instance.cpuPlatform()); + assertSame(serviceMockReturnsOptions, instance.compute()); + } + + @Test + public void testToAndFromPb() { + initializeExpectedInstance(8); + compareInstance(expectedInstance, + Instance.fromPb(serviceMockReturnsOptions, expectedInstance.toPb())); + Instance instance = new Instance.Builder(serviceMockReturnsOptions, INSTANCE_ID, MACHINE_TYPE, + ATTACHED_DISK, NETWORK_INTERFACE).build(); + compareInstance(instance, Instance.fromPb(serviceMockReturnsOptions, instance.toPb())); + } + + @Test + public void testDeleteOperation() { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.delete(INSTANCE_ID)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.delete()); + } + + @Test + public void testDeleteNull() { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + expect(compute.delete(INSTANCE_ID)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.delete()); + } + + @Test + public void testExists_True() throws Exception { + initializeExpectedInstance(1); + InstanceOption[] expectedOptions = {InstanceOption.fields()}; + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(INSTANCE_ID, expectedOptions)).andReturn(expectedInstance); + replay(compute); + initializeInstance(); + assertTrue(instance.exists()); + verify(compute); + } + + @Test + public void testExists_False() throws Exception { + initializeExpectedInstance(1); + InstanceOption[] expectedOptions = {InstanceOption.fields()}; + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(INSTANCE_ID, expectedOptions)).andReturn(null); + replay(compute); + initializeInstance(); + assertFalse(instance.exists()); + verify(compute); + } + + @Test + public void testReload() throws Exception { + initializeExpectedInstance(3); + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(INSTANCE_ID)).andReturn(expectedInstance); + replay(compute); + initializeInstance(); + Instance updatedInstance = instance.reload(); + compareInstance(expectedInstance, updatedInstance); + verify(compute); + } + + @Test + public void testReloadNull() throws Exception { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(INSTANCE_ID)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.reload()); + verify(compute); + } + + @Test + public void testReloadWithOptions() throws Exception { + initializeExpectedInstance(3); + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(INSTANCE_ID, InstanceOption.fields())).andReturn(expectedInstance); + replay(compute); + initializeInstance(); + Instance updateInstance = instance.reload(InstanceOption.fields()); + compareInstance(expectedInstance, updateInstance); + verify(compute); + } + + @Test + public void testAddAccessConfig() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + AccessConfig accessConfig = AccessConfig.of("192.168.1.1"); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.addAccessConfig(INSTANCE_ID, "nic0", accessConfig)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.addAccessConfig("nic0", accessConfig)); + } + + @Test + public void testAddAccessConfig_Null() throws Exception { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + AccessConfig accessConfig = AccessConfig.of("192.168.1.1"); + expect(compute.addAccessConfig(INSTANCE_ID, "nic0", accessConfig)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.addAccessConfig("nic0", accessConfig)); + } + + @Test + public void testAddAccessConfigWithOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + AccessConfig accessConfig = AccessConfig.of("192.168.1.1"); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.addAccessConfig(INSTANCE_ID, "nic0", accessConfig, OperationOption.fields())) + .andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.addAccessConfig("nic0", accessConfig, OperationOption.fields())); + } + + @Test + public void testAttachDisk() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + PersistentDiskConfiguration configuration = PersistentDiskConfiguration.of(DISK_ID); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.attachDisk(INSTANCE_ID, configuration)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.attachDisk(configuration)); + } + + @Test + public void testAttachDisk_Null() throws Exception { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + PersistentDiskConfiguration configuration = PersistentDiskConfiguration.of(DISK_ID); + expect(compute.attachDisk(INSTANCE_ID, configuration)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.attachDisk(configuration)); + } + + @Test + public void testAttachDiskWithOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + PersistentDiskConfiguration configuration = PersistentDiskConfiguration.of(DISK_ID); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.attachDisk(INSTANCE_ID, configuration, OperationOption.fields())) + .andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.attachDisk(configuration, OperationOption.fields())); + } + + @Test + public void testAttachDiskName() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + PersistentDiskConfiguration configuration = PersistentDiskConfiguration.of(DISK_ID); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.attachDisk(INSTANCE_ID, "dev0", configuration)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.attachDisk("dev0", configuration)); + } + + @Test + public void testAttachDiskName_Null() throws Exception { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + PersistentDiskConfiguration configuration = PersistentDiskConfiguration.of(DISK_ID); + expect(compute.attachDisk(INSTANCE_ID, "dev0", configuration)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.attachDisk("dev0", configuration)); + } + + @Test + public void testAttachDiskNameWithOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + PersistentDiskConfiguration configuration = PersistentDiskConfiguration.of(DISK_ID); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.attachDisk(INSTANCE_ID, "dev0", configuration, OperationOption.fields())) + .andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.attachDisk("dev0", configuration, OperationOption.fields())); + } + + @Test + public void testAttachDiskNameIndex() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + PersistentDiskConfiguration configuration = PersistentDiskConfiguration.of(DISK_ID); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.attachDisk(INSTANCE_ID, "dev0", configuration, 1)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.attachDisk("dev0", configuration, 1)); + } + + @Test + public void testAttachDiskNameIndex_Null() throws Exception { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + PersistentDiskConfiguration configuration = PersistentDiskConfiguration.of(DISK_ID); + expect(compute.attachDisk(INSTANCE_ID, "dev0", configuration, 1)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.attachDisk("dev0", configuration, 1)); + } + + @Test + public void testAttachDiskNameIndexWithOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + PersistentDiskConfiguration configuration = PersistentDiskConfiguration.of(DISK_ID); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.attachDisk(INSTANCE_ID, "dev0", configuration, 1, OperationOption.fields())) + .andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, + instance.attachDisk("dev0", configuration, 1, OperationOption.fields())); + } + + @Test + public void testDeleteAccessConfig() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.deleteAccessConfig(INSTANCE_ID, "nic0", "NAT")).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.deleteAccessConfig("nic0", "NAT")); + } + + @Test + public void testDeleteAccessConfig_Null() throws Exception { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + expect(compute.deleteAccessConfig(INSTANCE_ID, "nic0", "NAT")).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.deleteAccessConfig("nic0", "NAT")); + } + + @Test + public void testDeleteAccessConfigWithOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.deleteAccessConfig(INSTANCE_ID, "nic0", "NAT", OperationOption.fields())) + .andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.deleteAccessConfig("nic0", "NAT", OperationOption.fields())); + } + + @Test + public void testDetachDisk() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.detachDisk(INSTANCE_ID, "dev0")).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.detachDisk("dev0")); + } + + @Test + public void testDetachDisk_Null() throws Exception { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + expect(compute.detachDisk(INSTANCE_ID, "dev0")).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.detachDisk("dev0")); + } + + @Test + public void testDetachDiskWithOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.detachDisk(INSTANCE_ID, "dev0", OperationOption.fields())).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.detachDisk("dev0", OperationOption.fields())); + } + + @Test + public void testGetSerialPortOutputWithNumber() throws Exception { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + expect(compute.getSerialPortOutput(INSTANCE_ID, 2)).andReturn("output"); + replay(compute); + initializeInstance(); + assertSame("output", instance.getSerialPortOutput(2)); + } + + @Test + public void testGetSerialPortOutput() throws Exception { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + expect(compute.getSerialPortOutput(INSTANCE_ID)).andReturn("output"); + replay(compute); + initializeInstance(); + assertSame("output", instance.getSerialPortOutput()); + } + + @Test + public void testResetOperation() { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.reset(INSTANCE_ID)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.reset()); + } + + @Test + public void testResetNull() { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + expect(compute.reset(INSTANCE_ID)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.reset()); + } + + @Test + public void testSetDiskAutodelete() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.setDiskAutoDelete(INSTANCE_ID, "dev0", true)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.setDiskAutoDelete("dev0", true)); + } + + @Test + public void testSetDiskAutodelete_Null() throws Exception { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + expect(compute.setDiskAutoDelete(INSTANCE_ID, "dev0", false)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.setDiskAutoDelete("dev0", false)); + } + + @Test + public void testSetDiskAutodeleteWithOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.setDiskAutoDelete(INSTANCE_ID, "dev0", true, OperationOption.fields())) + .andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.setDiskAutoDelete("dev0", true, OperationOption.fields())); + } + + @Test + public void testSetMachineType() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.setMachineType(INSTANCE_ID, MACHINE_TYPE)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.setMachineType(MACHINE_TYPE)); + } + + @Test + public void testSetMachineType_Null() throws Exception { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + expect(compute.setMachineType(INSTANCE_ID, MACHINE_TYPE)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.setMachineType(MACHINE_TYPE)); + } + + @Test + public void testSetMachineTypeWithOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.setMachineType(INSTANCE_ID, MACHINE_TYPE, OperationOption.fields())) + .andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.setMachineType(MACHINE_TYPE, OperationOption.fields())); + } + + @Test + public void testSetMetadata() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + Metadata metadata = Metadata.builder().add("k", "v").fingerprint("fingerprint").build(); + expect(compute.setMetadata(INSTANCE_ID, metadata)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.setMetadata(metadata)); + } + + @Test + public void testSetMetadata_Null() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Metadata metadata = Metadata.builder().add("k", "v").fingerprint("fingerprint").build(); + expect(compute.setMetadata(INSTANCE_ID, metadata)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.setMetadata(metadata)); + } + + @Test + public void testSetMetadataWithOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + Metadata metadata = Metadata.builder().add("k", "v").fingerprint("fingerprint").build(); + expect(compute.setMetadata(INSTANCE_ID, metadata, OperationOption.fields())) + .andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.setMetadata(metadata, OperationOption.fields())); + } + + @Test + public void testSetMetadataFromMap() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + Map metadataMap = ImmutableMap.of("k", "v"); + Metadata metadata = Metadata.builder().values(metadataMap).fingerprint("fingerprint").build(); + expect(compute.setMetadata(INSTANCE_ID, metadata)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.setMetadata(metadataMap)); + } + + @Test + public void testSetMetadataFromMap_Null() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Map metadataMap = ImmutableMap.of("k", "v"); + Metadata metadata = Metadata.builder().values(metadataMap).fingerprint("fingerprint").build(); + expect(compute.setMetadata(INSTANCE_ID, metadata)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.setMetadata(metadataMap)); + } + + @Test + public void testSetMetadataFromMapWithOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + Map metadataMap = ImmutableMap.of("k", "v"); + Metadata metadata = Metadata.builder().values(metadataMap).fingerprint("fingerprint").build(); + expect(compute.setMetadata(INSTANCE_ID, metadata, OperationOption.fields())) + .andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.setMetadata(metadataMap, OperationOption.fields())); + } + + @Test + public void testSetSchedulingOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + SchedulingOptions schedulingOptions = SchedulingOptions.standard(true, Maintenance.MIGRATE); + expect(compute.setSchedulingOptions(INSTANCE_ID, schedulingOptions)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.setSchedulingOptions(schedulingOptions)); + } + + @Test + public void testSetSchedulingOptions_Null() throws Exception { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + SchedulingOptions schedulingOptions = SchedulingOptions.standard(true, Maintenance.MIGRATE); + expect(compute.setSchedulingOptions(INSTANCE_ID, schedulingOptions)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.setSchedulingOptions(schedulingOptions)); + } + + @Test + public void testSetSchedulingOptionsWithOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + SchedulingOptions schedulingOptions = SchedulingOptions.standard(true, Maintenance.MIGRATE); + expect(compute.setSchedulingOptions(INSTANCE_ID, schedulingOptions, OperationOption.fields())) + .andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, + instance.setSchedulingOptions(schedulingOptions, OperationOption.fields())); + } + + @Test + public void testSetTags() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + Tags tags = Tags.builder().values("v1", "v2").fingerprint("fingerprint").build(); + expect(compute.setTags(INSTANCE_ID, tags)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.setTags(tags)); + } + + @Test + public void testSetTags_Null() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Tags tags = Tags.builder().values("v1", "v2").fingerprint("fingerprint").build(); + expect(compute.setTags(INSTANCE_ID, tags)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.setTags(tags)); + } + + @Test + public void testSetTagsWithOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + Tags tags = Tags.builder().values("v1", "v2").fingerprint("fingerprint").build(); + expect(compute.setTags(INSTANCE_ID, tags, OperationOption.fields())).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.setTags(tags, OperationOption.fields())); + } + + @Test + public void testSetTagsFromList() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + List tagList = ImmutableList.of("v1", "v2"); + Tags tags = Tags.builder().values(tagList).fingerprint("fingerprint").build(); + expect(compute.setTags(INSTANCE_ID, tags)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.setTags(tagList)); + } + + @Test + public void testSetTagsFromList_Null() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + List tagList = ImmutableList.of("v1", "v2"); + Tags tags = Tags.builder().values(tagList).fingerprint("fingerprint").build(); + expect(compute.setTags(INSTANCE_ID, tags)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.setTags(tagList)); + } + + @Test + public void testSetTagsFromListWithOptions() throws Exception { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + List tagList = ImmutableList.of("v1", "v2"); + Tags tags = Tags.builder().values(tagList).fingerprint("fingerprint").build(); + expect(compute.setTags(INSTANCE_ID, tags, OperationOption.fields())).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.setTags(tagList, OperationOption.fields())); + } + + @Test + public void testStartOperation() { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.start(INSTANCE_ID)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.start()); + } + + @Test + public void testStartNull() { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + expect(compute.start(INSTANCE_ID)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.start()); + } + + @Test + public void testStopOperation() { + initializeExpectedInstance(2); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(ZoneOperationId.of("project", "op")) + .build(); + expect(compute.stop(INSTANCE_ID)).andReturn(operation); + replay(compute); + initializeInstance(); + assertSame(operation, instance.stop()); + } + + @Test + public void testStopNull() { + initializeExpectedInstance(1); + expect(compute.options()).andReturn(mockOptions); + expect(compute.stop(INSTANCE_ID)).andReturn(null); + replay(compute); + initializeInstance(); + assertNull(instance.stop()); + } + + public void compareInstance(Instance expected, Instance value) { + assertEquals(expected, value); + assertEquals(expected.compute().options(), value.compute().options()); + assertEquals(expected.id(), value.id()); + assertEquals(expected.instanceId(), value.instanceId()); + assertEquals(expected.creationTimestamp(), value.creationTimestamp()); + assertEquals(expected.description(), value.description()); + assertEquals(expected.status(), value.status()); + assertEquals(expected.statusMessage(), value.statusMessage()); + assertEquals(expected.tags(), value.tags()); + assertEquals(expected.machineType(), value.machineType()); + assertEquals(expected.canIpForward(), value.canIpForward()); + assertEquals(expected.networkInterfaces(), value.networkInterfaces()); + assertEquals(expected.attachedDisks(), value.attachedDisks()); + assertEquals(expected.metadata(), value.metadata()); + assertEquals(expected.serviceAccounts(), value.serviceAccounts()); + assertEquals(expected.schedulingOptions(), value.schedulingOptions()); + assertEquals(expected.cpuPlatform(), value.cpuPlatform()); + 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 92b1128ac6c4..5b5b97142a3d 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 @@ -193,6 +193,9 @@ public class SerializationTest { private static final SchedulingOptions SCHEDULING_OPTIONS = SchedulingOptions.preemptible(); private static final InstanceInfo INSTANCE_INFO = InstanceInfo.of(INSTANCE_ID, MACHINE_TYPE_ID, ATTACHED_DISK, NETWORK_INTERFACE); + private static final Instance INSTANCE = + new Instance.Builder(COMPUTE, INSTANCE_ID, MACHINE_TYPE_ID, ATTACHED_DISK, NETWORK_INTERFACE) + .build(); private static final Compute.DiskTypeOption DISK_TYPE_OPTION = Compute.DiskTypeOption.fields(); private static final Compute.DiskTypeFilter DISK_TYPE_FILTER = @@ -263,6 +266,14 @@ public class SerializationTest { Compute.NetworkFilter.equals(Compute.NetworkField.SELF_LINK, "selfLink"); private static final Compute.NetworkListOption NETWORK_LIST_OPTION = Compute.NetworkListOption.filter(NETWORK_FILTER); + private static final Compute.InstanceOption INSTANCE_OPTION = + Compute.InstanceOption.fields(); + private static final Compute.InstanceFilter INSTANCE_FILTER = + Compute.InstanceFilter.equals(Compute.InstanceField.SELF_LINK, "selfLink"); + private static final Compute.InstanceListOption INSTANCE_LIST_OPTION = + Compute.InstanceListOption.filter(INSTANCE_FILTER); + private static final Compute.InstanceAggregatedListOption INSTANCE_AGGREGATED_LIST_OPTION = + Compute.InstanceAggregatedListOption.filter(INSTANCE_FILTER); @Test public void testServiceOptions() throws Exception { @@ -296,7 +307,7 @@ public void testModelAndRequests() throws Exception { STANDARD_NETWORK_CONFIGURATION, SUBNET_NETWORK_CONFIGURATION, NETWORK_INFO, NETWORK, ACCESS_CONFIG, NETWORK_INTERFACE, CREATE_DISK_CONFIGURATION, PERSISTENT_DISK_CONFIGURATION, SCRATCH_DISK_CONFIGURATION, ATTACHED_DISK, TAGS, METADATA, SERVICE_ACCOUNT, - SCHEDULING_OPTIONS, INSTANCE_INFO, DISK_TYPE_OPTION, DISK_TYPE_FILTER, + SCHEDULING_OPTIONS, INSTANCE_INFO, INSTANCE, 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, @@ -305,7 +316,8 @@ public void testModelAndRequests() throws Exception { 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, SUBNETWORK_OPTION, SUBNETWORK_FILTER, SUBNETWORK_LIST_OPTION, - SUBNETWORK_AGGREGATED_LIST_OPTION, NETWORK_OPTION, NETWORK_FILTER, NETWORK_LIST_OPTION}; + SUBNETWORK_AGGREGATED_LIST_OPTION, NETWORK_OPTION, NETWORK_FILTER, NETWORK_LIST_OPTION, + INSTANCE_OPTION, INSTANCE_FILTER, INSTANCE_LIST_OPTION, INSTANCE_AGGREGATED_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/it/ITComputeTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/it/ITComputeTest.java index d47d0fb6082b..00a26cf82602 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 @@ -23,11 +23,18 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.gcloud.Page; import com.google.gcloud.compute.Address; import com.google.gcloud.compute.AddressId; import com.google.gcloud.compute.AddressInfo; +import com.google.gcloud.compute.AttachedDisk; +import com.google.gcloud.compute.AttachedDisk.AttachedDiskConfiguration; +import com.google.gcloud.compute.AttachedDisk.CreateDiskConfiguration; +import com.google.gcloud.compute.AttachedDisk.PersistentDiskConfiguration; +import com.google.gcloud.compute.AttachedDisk.ScratchDiskConfiguration; import com.google.gcloud.compute.Compute; import com.google.gcloud.compute.DeprecationStatus; import com.google.gcloud.compute.Disk; @@ -43,17 +50,25 @@ import com.google.gcloud.compute.ImageDiskConfiguration; import com.google.gcloud.compute.ImageId; import com.google.gcloud.compute.ImageInfo; +import com.google.gcloud.compute.Instance; +import com.google.gcloud.compute.InstanceId; +import com.google.gcloud.compute.InstanceInfo; import com.google.gcloud.compute.License; import com.google.gcloud.compute.LicenseId; import com.google.gcloud.compute.MachineType; +import com.google.gcloud.compute.MachineTypeId; 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.NetworkInterface; +import com.google.gcloud.compute.NetworkInterface.AccessConfig; import com.google.gcloud.compute.Operation; import com.google.gcloud.compute.Region; import com.google.gcloud.compute.RegionAddressId; import com.google.gcloud.compute.RegionOperationId; +import com.google.gcloud.compute.SchedulingOptions; +import com.google.gcloud.compute.SchedulingOptions.Maintenance; import com.google.gcloud.compute.Snapshot; import com.google.gcloud.compute.SnapshotDiskConfiguration; import com.google.gcloud.compute.SnapshotId; @@ -75,6 +90,8 @@ import org.junit.rules.Timeout; import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.Set; public class ITComputeTest { @@ -1599,4 +1616,307 @@ public void testAggregatedListSubnetworks() throws InterruptedException { } assertNull(compute.getNetwork(networkName)); } + + @Test + public void testCreateGetAndDeleteInstance() throws InterruptedException { + String instanceName = BASE_RESOURCE_NAME + "create-and-get-instance"; + String addressName = BASE_RESOURCE_NAME + "create-and-get-instance-address"; + // Create an address to assign to the instance + AddressId addressId = RegionAddressId.of(REGION, addressName); + AddressInfo addressInfo = AddressInfo.of(addressId); + Operation operation = compute.create(addressInfo); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + Address address = compute.get(addressId); + // Create an instance + InstanceId instanceId = InstanceId.of(ZONE, instanceName); + NetworkId networkId = NetworkId.of("default"); + NetworkInterface networkInterface = NetworkInterface.builder(networkId) + .accessConfigurations(AccessConfig.builder().name("NAT").natIp(address.address()).build()) + .build(); + AttachedDisk disk1 = AttachedDisk.of("dev0", + CreateDiskConfiguration.builder(IMAGE_ID).autoDelete(true).build()); + AttachedDisk disk2 = + AttachedDisk.of("dev1", ScratchDiskConfiguration.of(DiskTypeId.of(ZONE, DISK_TYPE))); + InstanceInfo instanceInfo = + InstanceInfo.builder(instanceId, MachineTypeId.of(ZONE, "n1-standard-1")) + .attachedDisks(disk1, disk2) + .networkInterfaces(networkInterface) + .build(); + operation = compute.create(instanceInfo); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + // test get + Instance remoteInstance = compute.get(instanceId); + assertEquals(instanceName, remoteInstance.instanceId().instance()); + assertEquals(ZONE, remoteInstance.instanceId().zone()); + assertEquals(InstanceInfo.Status.RUNNING, remoteInstance.status()); + assertEquals("n1-standard-1", remoteInstance.machineType().type()); + assertEquals(ZONE, remoteInstance.machineType().zone()); + assertNotNull(remoteInstance.creationTimestamp()); + Set deviceSet = ImmutableSet.of("dev0", "dev1"); + assertEquals(2, remoteInstance.attachedDisks().size()); + for (AttachedDisk remoteAttachedDisk : remoteInstance.attachedDisks()) { + assertTrue(deviceSet.contains(remoteAttachedDisk.deviceName())); + } + assertEquals(AttachedDiskConfiguration.Type.PERSISTENT, + remoteInstance.attachedDisks().get(0).configuration().type()); + PersistentDiskConfiguration remoteConfiguration = + remoteInstance.attachedDisks().get(0).configuration(); + assertEquals(instanceName, remoteConfiguration.sourceDisk().disk()); + assertEquals(ZONE, remoteConfiguration.sourceDisk().zone()); + assertTrue(remoteConfiguration.boot()); + assertTrue(remoteConfiguration.autoDelete()); + assertEquals(1, remoteInstance.networkInterfaces().size()); + NetworkInterface remoteNetworkInterface = remoteInstance.networkInterfaces().get(0); + assertNotNull(remoteNetworkInterface.name()); + assertEquals("default", remoteNetworkInterface.network().network()); + List remoteAccessConfigurations = remoteNetworkInterface.accessConfigurations(); + assertNotNull(remoteAccessConfigurations); + assertEquals(1, remoteAccessConfigurations.size()); + AccessConfig remoteAccessConfig = remoteAccessConfigurations.get(0); + assertEquals(address.address(), remoteAccessConfig.natIp()); + assertEquals("NAT", remoteAccessConfig.name()); + assertNotNull(remoteInstance.metadata()); + assertNotNull(remoteInstance.tags()); + // test get with selected fields + remoteInstance = compute.get(instanceId, + Compute.InstanceOption.fields(Compute.InstanceField.CREATION_TIMESTAMP)); + assertEquals(instanceName, remoteInstance.instanceId().instance()); + assertEquals(ZONE, remoteInstance.instanceId().zone()); + assertNull(remoteInstance.machineType()); + assertNotNull(remoteInstance.creationTimestamp()); + assertNull(remoteInstance.attachedDisks()); + assertNull(remoteInstance.networkInterfaces()); + assertNull(remoteInstance.metadata()); + assertNull(remoteInstance.tags()); + // test get default serial port output + String serialPortOutput = remoteInstance.getSerialPortOutput(); + assertNotNull(serialPortOutput); + // test get serial port output by number + String newSerialPortOutput = remoteInstance.getSerialPortOutput(1); + assertTrue(newSerialPortOutput.contains(serialPortOutput)); + operation = remoteInstance.delete(); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + assertNull(compute.get(instanceId)); + address.delete(); + } + + @Test + public void testStartStopAndResetInstance() throws InterruptedException { + String instanceName = BASE_RESOURCE_NAME + "start-stop-reset-instance"; + InstanceId instanceId = InstanceId.of(ZONE, instanceName); + NetworkId networkId = NetworkId.of("default"); + NetworkInterface networkInterface = NetworkInterface.builder(networkId).build(); + AttachedDisk disk = AttachedDisk.of("dev0", + CreateDiskConfiguration.builder(IMAGE_ID).autoDelete(true).build()); + InstanceInfo instanceInfo = + InstanceInfo.builder(instanceId, MachineTypeId.of(ZONE, MACHINE_TYPE)) + .attachedDisks(disk) + .networkInterfaces(networkInterface) + .build(); + Operation operation = compute.create(instanceInfo); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + Instance remoteInstance = + compute.get(instanceId, Compute.InstanceOption.fields(Compute.InstanceField.STATUS)); + assertEquals(InstanceInfo.Status.RUNNING, remoteInstance.status()); + operation = remoteInstance.stop(); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + remoteInstance = + compute.get(instanceId, Compute.InstanceOption.fields(Compute.InstanceField.STATUS)); + assertEquals(InstanceInfo.Status.TERMINATED, remoteInstance.status()); + operation = remoteInstance.start(); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + remoteInstance = + compute.get(instanceId, Compute.InstanceOption.fields(Compute.InstanceField.STATUS)); + assertEquals(InstanceInfo.Status.RUNNING, remoteInstance.status()); + operation = remoteInstance.reset(); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + remoteInstance = + compute.get(instanceId, Compute.InstanceOption.fields(Compute.InstanceField.STATUS)); + assertEquals(InstanceInfo.Status.RUNNING, remoteInstance.status()); + remoteInstance.delete(); + } + + @Test + public void testSetInstanceProperties() throws InterruptedException { + String instanceName = BASE_RESOURCE_NAME + "set-properties-instance"; + InstanceId instanceId = InstanceId.of(ZONE, instanceName); + NetworkId networkId = NetworkId.of("default"); + NetworkInterface networkInterface = NetworkInterface.builder(networkId).build(); + AttachedDisk disk = AttachedDisk.of("dev0", + CreateDiskConfiguration.builder(IMAGE_ID).autoDelete(true).build()); + InstanceInfo instanceInfo = + InstanceInfo.builder(instanceId, MachineTypeId.of(ZONE, MACHINE_TYPE)) + .attachedDisks(disk) + .networkInterfaces(networkInterface) + .build(); + Operation operation = compute.create(instanceInfo); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + Instance remoteInstance = compute.get(instanceId); + // test set tags + List tags = ImmutableList.of("tag1", "tag2"); + operation = remoteInstance.setTags(tags); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + remoteInstance = compute.get(instanceId); + assertEquals(tags, remoteInstance.tags().values()); + // test set metadata + Map metadata = ImmutableMap.of("key", "value"); + operation = remoteInstance.setMetadata(metadata); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + remoteInstance = compute.get(instanceId); + assertEquals(metadata, remoteInstance.metadata().values()); + // test set machine type + operation = remoteInstance.stop(); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + operation = remoteInstance.setMachineType(MachineTypeId.of(ZONE, "n1-standard-1")); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + remoteInstance = compute.get(instanceId); + assertEquals("n1-standard-1", remoteInstance.machineType().type()); + assertEquals(ZONE, remoteInstance.machineType().zone()); + // test set scheduling options + SchedulingOptions options = SchedulingOptions.standard(false, Maintenance.TERMINATE); + operation = remoteInstance.setSchedulingOptions(options); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + remoteInstance = compute.get(instanceId); + assertEquals(options, remoteInstance.schedulingOptions()); + remoteInstance.delete(); + } + + @Test + public void testAttachAndDetachDisk() throws InterruptedException { + String instanceName = BASE_RESOURCE_NAME + "attach-and-detach-disk-instance"; + String diskName = BASE_RESOURCE_NAME + "attach-and-detach-disk"; + InstanceId instanceId = InstanceId.of(ZONE, instanceName); + NetworkId networkId = NetworkId.of("default"); + NetworkInterface networkInterface = NetworkInterface.builder(networkId).build(); + AttachedDisk disk = AttachedDisk.of("dev0", + CreateDiskConfiguration.builder(IMAGE_ID).autoDelete(true).build()); + InstanceInfo instanceInfo = + InstanceInfo.builder(instanceId, MachineTypeId.of(ZONE, MACHINE_TYPE)) + .attachedDisks(disk) + .networkInterfaces(networkInterface) + .build(); + Operation instanceOperation = compute.create(instanceInfo); + DiskId diskId = DiskId.of(ZONE, diskName); + Operation diskOperation = compute.create(DiskInfo.of(diskId, + StandardDiskConfiguration.of(DiskTypeId.of(ZONE, "pd-ssd")))); + while (!instanceOperation.isDone()) { + Thread.sleep(1000L); + } + while (!diskOperation.isDone()) { + Thread.sleep(1000L); + } + Instance remoteInstance = compute.get(instanceId); + // test attach disk + instanceOperation = remoteInstance.attachDisk("dev1", + PersistentDiskConfiguration.builder(diskId).build()); + while (!instanceOperation.isDone()) { + Thread.sleep(1000L); + } + remoteInstance = compute.get(instanceId); + Set deviceSet = ImmutableSet.of("dev0", "dev1"); + assertEquals(2, remoteInstance.attachedDisks().size()); + for (AttachedDisk remoteAttachedDisk : remoteInstance.attachedDisks()) { + assertTrue(deviceSet.contains(remoteAttachedDisk.deviceName())); + } + // test set disk auto-delete + instanceOperation = remoteInstance.setDiskAutoDelete("dev1", true); + while (!instanceOperation.isDone()) { + Thread.sleep(1000L); + } + remoteInstance = compute.get(instanceId); + for (AttachedDisk remoteAttachedDisk : remoteInstance.attachedDisks()) { + assertTrue(deviceSet.contains(remoteAttachedDisk.deviceName())); + assertTrue(remoteAttachedDisk.configuration().autoDelete()); + } + // test detach disk + instanceOperation = remoteInstance.detachDisk("dev1"); + while (!instanceOperation.isDone()) { + Thread.sleep(1000L); + } + remoteInstance = compute.get(instanceId); + assertEquals(1, remoteInstance.attachedDisks().size()); + assertEquals("dev0", remoteInstance.attachedDisks().get(0).deviceName()); + remoteInstance.delete(); + } + + @Test + public void testAddAndRemoveAccessConfig() throws InterruptedException { + String instanceName = BASE_RESOURCE_NAME + "add-and-remove-access-instance"; + String addressName = BASE_RESOURCE_NAME + "add-and-remove-access-address"; + InstanceId instanceId = InstanceId.of(ZONE, instanceName); + NetworkId networkId = NetworkId.of("default"); + NetworkInterface networkInterface = NetworkInterface.builder(networkId).build(); + AttachedDisk disk = AttachedDisk.of("dev0", + CreateDiskConfiguration.builder(IMAGE_ID).autoDelete(true).build()); + InstanceInfo instanceInfo = + InstanceInfo.builder(instanceId, MachineTypeId.of(ZONE, MACHINE_TYPE)) + .attachedDisks(disk) + .networkInterfaces(networkInterface) + .build(); + Operation instanceOperation = compute.create(instanceInfo); + AddressId addressId = RegionAddressId.of(REGION, addressName); + AddressInfo addressInfo = AddressInfo.of(addressId); + Operation addressOperation = compute.create(addressInfo); + while (!addressOperation.isDone()) { + Thread.sleep(1000L); + } + while (!instanceOperation.isDone()) { + Thread.sleep(1000L); + } + while (!addressOperation.isDone()) { + Thread.sleep(1000L); + } + Address remoteAddress = compute.get(addressId); + Instance remoteInstance = compute.get(instanceId); + String networkInterfaceName = remoteInstance.networkInterfaces().get(0).name(); + // test add access config + AccessConfig accessConfig = AccessConfig.builder() + .natIp(remoteAddress.address()) + .name("NAT") + .build(); + instanceOperation = remoteInstance.addAccessConfig(networkInterfaceName, accessConfig); + while (!instanceOperation.isDone()) { + Thread.sleep(1000L); + } + remoteInstance = compute.get(instanceId); + List accessConfigurations = + remoteInstance.networkInterfaces().get(0).accessConfigurations(); + assertEquals(1, accessConfigurations.size()); + assertEquals("NAT", accessConfigurations.get(0).name()); + // test delete access config + instanceOperation = remoteInstance.deleteAccessConfig(networkInterfaceName, "NAT"); + while (!instanceOperation.isDone()) { + Thread.sleep(1000L); + } + remoteInstance = compute.get(instanceId); + assertTrue(remoteInstance.networkInterfaces().get(0).accessConfigurations().isEmpty()); + remoteInstance.delete(); + remoteAddress.delete(); + } }