diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AttachedDisk.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AttachedDisk.java new file mode 100644 index 000000000000..8bdf9f1e1f33 --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AttachedDisk.java @@ -0,0 +1,881 @@ +/* + * 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.api.services.compute.model.AttachedDiskInitializeParams; +import com.google.common.base.Function; +import com.google.common.base.MoreObjects; +import com.google.common.collect.Lists; + +import java.io.Serializable; +import java.util.List; +import java.util.Objects; + +/** + * A base class for disks attached to a Google Compute Engine instance. To create a new disk to + * attach when an image is created use {@link CreateAttachedDisk}. To attach an existing persistent + * disk use {@link PersistentAttachedDisk}. To attach a scratch disk use + * {@link ScratchAttachedDisk}. + */ +public abstract class AttachedDisk implements Serializable { + + static final Function + FROM_PB_FUNCTION = + new Function() { + @Override + public AttachedDisk apply( + com.google.api.services.compute.model.AttachedDisk pb) { + return AttachedDisk.fromPb(pb); + } + }; + static final Function + TO_PB_FUNCTION = + new Function() { + @Override + public com.google.api.services.compute.model.AttachedDisk apply( + AttachedDisk attachedDisk) { + return attachedDisk.toPb(); + } + }; + private static final long serialVersionUID = 2969789134157943798L; + + private final String deviceName; + private final Integer index; + private final List licenses; + private final Type type; + private final InterfaceType interfaceType; + private final Boolean boot; + private final Boolean autoDelete; + private final Mode mode; + + /** + * Specifies the type of the attached disk. + */ + public enum Type { + /** + * A persistent disk attached to a VM instance. Such an attached disk must already exist or + * can be created along with the instance by using {@link CreateAttachedDisk}. A persistent disk + * an be attached to other VM instances. + */ + PERSISTENT, + + /** + * A scratch disk is created with the VM instance it is attached to. Scratch disks are only + * available to their VM instance. + */ + SCRATCH + } + + /** + * Specifies the disk interface to use for attaching this disk, which is either {@code SCSI} + * or {@code NVME}. Persistent disks must always use {@code SCSI}. Scratch SSDs can use either + * {@code NVME} or {@code SCSI}. + */ + public enum InterfaceType { + SCSI, + NVME + } + + /** + * Specifies the mode in which to attach the disk. + */ + public enum Mode { + /** + * The instance can both read and write to the disk. + */ + READ_WRITE, + + /** + * The instance is only allowed to read the disk. + */ + READ_ONLY + } + + /** + * Base builder for attached disks. + * + * @param the attached disk type + * @param the attached disk builder + */ + public abstract static class Builder> { + + private String deviceName; + private Integer index; + private List licenses; + private Type type; + private InterfaceType interfaceType; // move to scratch? + private Boolean boot; // move to persistent and create disk? + private Boolean autoDelete; // move to persistent and create disk? + private Mode mode; + + Builder(Type type) { + this.type = type; + } + + Builder(com.google.api.services.compute.model.AttachedDisk diskPb) { + deviceName = diskPb.getDeviceName(); + index = diskPb.getIndex(); + type = Type.valueOf(diskPb.getType()); + if (diskPb.getLicenses() != null) { + licenses = Lists.transform(diskPb.getLicenses(), LicenseId.FROM_URL_FUNCTION); + } + if (diskPb.getInterface() != null) { + interfaceType = InterfaceType.valueOf(diskPb.getInterface()); + } + if (diskPb.getMode() != null) { + mode = Mode.valueOf(diskPb.getMode()); + } + boot = diskPb.getBoot(); + autoDelete = diskPb.getAutoDelete(); + } + + Builder(AttachedDisk attachedDisk) { + this.deviceName = attachedDisk.deviceName; + this.index = attachedDisk.index; + this.licenses = attachedDisk.licenses; + this.type = attachedDisk.type; + this.interfaceType = attachedDisk.interfaceType; + this.boot = attachedDisk.boot; + this.autoDelete = attachedDisk.autoDelete; + this.mode = attachedDisk.mode; + } + + @SuppressWarnings("unchecked") + protected B self() { + return (B) this; + } + + /** + * Sets the unique device name of your choice that is reflected into the + * {@code /dev/disk/by-id/google-*} tree of a Linux operating system running within the + * instance. This name can be used to reference the device for mounting, resizing, and so on, + * from within the instance. If not specified, the service chooses a default device name to + * apply to this disk, in the form {@code persistent-disks-x}, where x is a number assigned by + * Google Compute Engine. + */ + public B deviceName(String deviceName) { + this.deviceName = deviceName; + return self(); + } + + /** + * Sets a zero-based index to this disk, where 0 is reserved for the boot disk. For example, + * if you have many disks attached to an instance, each disk would have an unique index number. + * If not specified, the service will choose an appropriate value. + */ + public B index(Integer index) { + this.index = index; + return self(); + } + + B licenses(List licenses) { + this.licenses = licenses; + return self(); + } + + B type(Type type) { + this.type = type; + return self(); + } + + B interfaceType(InterfaceType interfaceType) { + this.interfaceType = interfaceType; + return self(); + } + + B boot(Boolean boot) { + this.boot = boot; + return self(); + } + + B autoDelete(Boolean autoDelete) { + this.autoDelete = autoDelete; + return self(); + } + + B mode(Mode mode) { + this.mode = mode; + return self(); + } + + /** + * Creates an object. + */ + public abstract T build(); + } + + /** + * A class for attached disks created from existing persistent disks. Persistent disks are always + * attached using the {@link InterfaceType#SCSI}. + */ + public static final class PersistentAttachedDisk extends AttachedDisk { + + private static final long serialVersionUID = 6367613188140104726L; + + private final DiskId sourceDisk; + + /** + * A builder for {@code PersistentAttachedDisk} objects. + */ + public static final class Builder extends AttachedDisk.Builder { + + private DiskId sourceDisk; + + private Builder(PersistentAttachedDisk attachedDisk) { + super(attachedDisk); + this.sourceDisk = attachedDisk.sourceDisk; + } + + private Builder(DiskId sourceDisk) { + super(Type.PERSISTENT); + this.sourceDisk = checkNotNull(sourceDisk); + } + + private Builder(com.google.api.services.compute.model.AttachedDisk diskPb) { + super(diskPb); + this.sourceDisk = DiskId.fromUrl(diskPb.getSource()); + } + + /** + * Sets the identity of the persistent disk to be attached. + */ + public Builder sourceDisk(DiskId sourceDisk) { + this.sourceDisk = checkNotNull(sourceDisk); + return this; + } + + /** + * Sets the mode in which to attach this disk. If not specified, the disk is attached in + * {@link Mode#READ_WRITE} mode. + */ + @Override + public Builder mode(Mode mode) { + super.mode(mode); + return this; + } + + /** + * Sets whether to use the attached disk as a boot disk. If {@code true} the virtual machine + * will use the first partition of the disk for its root filesystem. If not specified, the + * disk is not bootable. + */ + public Builder boot(boolean boot) { + super.boot(boot); + return this; + } + + /** + * Sets whether the disk should auto-delete when the instance to which it's attached is + * deleted. If not specified, the disk is not deleted automatically. + */ + public Builder autoDelete(boolean autoDelete) { + super.autoDelete(autoDelete); + return this; + } + + /** + * Creates a {@code PersistentAttachedDisk} object. + */ + public PersistentAttachedDisk build() { + return new PersistentAttachedDisk(this); + } + } + + PersistentAttachedDisk(Builder builder) { + super(builder); + this.sourceDisk = builder.sourceDisk; + } + + /** + * Returns the identity of the persistent disk to be attached. + */ + public DiskId sourceDisk() { + return sourceDisk; + } + + /** + * Returns a builder for the current attached disk. + */ + public Builder toBuilder() { + return new Builder(this); + } + + @Override + MoreObjects.ToStringHelper toStringHelper() { + return super.toStringHelper().add("sourceDisk", sourceDisk); + } + + @Override + public int hashCode() { + return Objects.hash(baseHashCode(), sourceDisk); + } + + @Override + public boolean equals(Object obj) { + return obj == this + || obj != null + && obj.getClass().equals(PersistentAttachedDisk.class) + && baseEquals((PersistentAttachedDisk) obj); + } + + @Override + PersistentAttachedDisk setProjectId(String projectId) { + if (sourceDisk.project() != null) { + return this; + } + return toBuilder().sourceDisk(sourceDisk.setProjectId(projectId)).build(); + } + + @Override + com.google.api.services.compute.model.AttachedDisk toPb() { + com.google.api.services.compute.model.AttachedDisk attachedDiskPb = super.toPb(); + attachedDiskPb.setSource(sourceDisk.selfLink()); + return attachedDiskPb; + } + + /** + * Returns a builder for a {@code PersistentAttachedDisk} object given the identity of the + * persistent disk to attach. + */ + public static Builder builder(DiskId sourceDisk) { + return new Builder(sourceDisk); + } + + /** + * Returns a {@code PersistentAttachedDisk} object given the identity of the persistent disk to + * attach. + */ + public static PersistentAttachedDisk of(DiskId sourceDisk) { + return builder(sourceDisk).build(); + } + + @SuppressWarnings("unchecked") + static PersistentAttachedDisk fromPb( + com.google.api.services.compute.model.AttachedDisk diskPb) { + return new Builder(diskPb).build(); + } + } + + /** + * A class for creating a boot persistent disk to attach to an instance. The attached disk is + * created along with the instance. Created persistent disks are always attached using the + * {@link InterfaceType#SCSI} and in {@link Mode#READ_WRITE} mode. + */ + public static final class CreateAttachedDisk extends AttachedDisk { + + private static final long serialVersionUID = 961995522284348824L; + + private final String diskName; + private final DiskTypeId diskType; + private final Long diskSizeGb; + private final ImageId sourceImage; + + /** + * A builder for {@code CreateAttachedDisk} objects. + */ + public static final class Builder extends AttachedDisk.Builder { + + private String diskName; + private DiskTypeId diskType; + private Long diskSizeGb; + private ImageId sourceImage; + + private Builder(ImageId sourceImage) { + super(Type.PERSISTENT); + boot(true); + this.sourceImage = checkNotNull(sourceImage); + } + + private Builder(CreateAttachedDisk attachedDisk) { + super(attachedDisk); + this.diskName = attachedDisk.diskName; + this.diskType = attachedDisk.diskType; + this.diskSizeGb = attachedDisk.diskSizeGb; + this.sourceImage = attachedDisk.sourceImage; + } + + private Builder(com.google.api.services.compute.model.AttachedDisk diskPb) { + super(diskPb); + AttachedDiskInitializeParams initializeParamsPb = diskPb.getInitializeParams(); + sourceImage = ImageId.fromUrl(initializeParamsPb.getSourceImage()); + if (initializeParamsPb.getDiskType() != null) { + diskType = DiskTypeId.fromUrl(initializeParamsPb.getDiskType()); + } + diskName = initializeParamsPb.getDiskName(); + diskSizeGb = initializeParamsPb.getDiskSizeGb(); + if (initializeParamsPb.getDiskType() != null) { + diskType = DiskTypeId.fromUrl(initializeParamsPb.getDiskType()); + } + } + + /** + * Sets the name to be assigned to the disk. If not specified, the disk is given the + * instance's name. + */ + public Builder diskName(String diskName) { + this.diskName = diskName; + return this; + } + + /** + * Sets the identity of the disk type. If not specified, {@code pd-standard} is used. + */ + public Builder diskType(DiskTypeId diskType) { + this.diskType = diskType; + return this; + } + + /** + * Sets the size of the persistent disk, in GB. + */ + public Builder diskSizeGb(Long diskSizeGb) { + this.diskSizeGb = diskSizeGb; + return this; + } + + /** + * Sets the identity of the source image used to create the disk. + */ + public Builder sourceImage(ImageId sourceImage) { + this.sourceImage = checkNotNull(sourceImage); + return this; + } + + /** + * Sets whether the disk should auto-delete when the instance to which it's attached is + * deleted. If not specified, the disk is not deleted automatically. + */ + @Override + public Builder autoDelete(Boolean autoDelete) { + super.autoDelete(autoDelete); + return this; + } + + /** + * Creates a {@code CreateAttachedDisk} object. + */ + public CreateAttachedDisk build() { + return new CreateAttachedDisk(this); + } + } + + CreateAttachedDisk(Builder builder) { + super(builder); + this.diskName = builder.diskName; + this.diskType = builder.diskType; + this.diskSizeGb = builder.diskSizeGb; + this.sourceImage = builder.sourceImage; + } + + /** + * Returns the name to be assigned to the disk. If not specified, the disk is given the + * instance's name. + */ + public String diskName() { + return diskName; + } + + /** + * Returns the identity of the disk type. If not specified, {@code pd-standard} is used. + */ + public DiskTypeId diskType() { + return diskType; + } + + /** + * Returns the size of the persistent disk, in GB. + */ + public Long diskSizeGb() { + return diskSizeGb; + } + + /** + * Returns the identity of the source image used to create the disk. + */ + public ImageId sourceImage() { + return sourceImage; + } + + /** + * Returns a builder for the current attached disk. + */ + public Builder toBuilder() { + return new Builder(this); + } + + @Override + MoreObjects.ToStringHelper toStringHelper() { + return super.toStringHelper() + .add("diskName", diskName) + .add("diskType", diskType) + .add("diskSizeGb", diskSizeGb) + .add("sourceImage", sourceImage); + } + + @Override + public int hashCode() { + return Objects.hash(baseHashCode(), diskName, diskType, diskSizeGb, sourceImage); + } + + @Override + public boolean equals(Object obj) { + return obj == this + || obj != null + && obj.getClass().equals(CreateAttachedDisk.class) + && baseEquals((CreateAttachedDisk) obj); + } + + @Override + CreateAttachedDisk setProjectId(String projectId) { + Builder builder = toBuilder(); + if (builder.diskType != null) { + builder.diskType(diskType.setProjectId(projectId)); + } + if (builder.sourceImage != null) { + builder.sourceImage(sourceImage.setProjectId(projectId)); + } + return builder.build(); + } + + @Override + com.google.api.services.compute.model.AttachedDisk toPb() { + AttachedDiskInitializeParams initializeParamsPb = new AttachedDiskInitializeParams(); + initializeParamsPb.setDiskName(diskName); + initializeParamsPb.setDiskSizeGb(diskSizeGb); + initializeParamsPb.setSourceImage(sourceImage.selfLink()); + if (diskType != null) { + initializeParamsPb.setDiskType(diskType.selfLink()); + } + com.google.api.services.compute.model.AttachedDisk attachedDiskPb = super.toPb(); + attachedDiskPb.setInitializeParams(initializeParamsPb); + return attachedDiskPb; + } + + /** + * Returns a builder for a {@code CreateAttachedDisk} object given the source image that will be + * used to create the disk. + */ + public static Builder builder(ImageId sourceImage) { + return new Builder(sourceImage); + } + + /** + * Returns a {@code CreateAttachedDisk} object given the source image that will be used to + * create the disk. + */ + public static CreateAttachedDisk of(ImageId sourceImage) { + return builder(sourceImage).build(); + } + + @SuppressWarnings("unchecked") + static CreateAttachedDisk fromPb(com.google.api.services.compute.model.AttachedDisk diskPb) { + return new Builder(diskPb).build(); + } + } + + /** + * A class to attach a scratch disk to an instance. The attached scratch disk is a non-bootable + * {@link Mode#READ_WRITE} disk that will be auto deleted with the instance to which it's + * attached. + */ + public static final class ScratchAttachedDisk extends AttachedDisk { + + private static final long serialVersionUID = -8445453507234691254L; + + private final DiskTypeId diskType; + + /** + * A builder for {@code ScratchDiskConfiguration} objects. + */ + public static final class Builder extends AttachedDisk.Builder { + + private DiskTypeId diskType; + + private Builder(DiskTypeId diskType) { + super(Type.SCRATCH); + boot(false); + autoDelete(true); + this.diskType = diskType; + } + + private Builder(ScratchAttachedDisk attachedDisk) { + super(attachedDisk); + this.diskType = attachedDisk.diskType; + } + + private Builder(com.google.api.services.compute.model.AttachedDisk diskPb) { + super(diskPb); + AttachedDiskInitializeParams initializeParamsPb = diskPb.getInitializeParams(); + if (initializeParamsPb != null && initializeParamsPb.getDiskType() != null) { + diskType = DiskTypeId.fromUrl(initializeParamsPb.getDiskType()); + } + } + + /** + * Sets the identity of the disk type. + */ + public Builder diskType(DiskTypeId diskType) { + this.diskType = checkNotNull(diskType); + return this; + } + + /** + * Sets the interface type. If not specified, {@code SCSI} is used. + */ + @Override + public Builder interfaceType(InterfaceType interfaceType) { + super.interfaceType(interfaceType); + return this; + } + + /** + * Creates a {@code ScratchAttachedDisk} object. + */ + public ScratchAttachedDisk build() { + return new ScratchAttachedDisk(this); + } + } + + ScratchAttachedDisk(Builder builder) { + super(builder); + this.diskType = builder.diskType; + } + + /** + * Returns the identity of the disk type for the scratch disk to attach. + */ + public DiskTypeId diskType() { + return diskType; + } + + /** + * Returns a builder for the current attached disk. + */ + public Builder toBuilder() { + return new Builder(this); + } + + @Override + MoreObjects.ToStringHelper toStringHelper() { + return super.toStringHelper().add("diskType", diskType); + } + + @Override + public int hashCode() { + return Objects.hash(baseHashCode()); + } + + @Override + public boolean equals(Object obj) { + return obj == this + || obj != null + && obj.getClass().equals(ScratchAttachedDisk.class) + && baseEquals((ScratchAttachedDisk) obj); + } + + @Override + ScratchAttachedDisk setProjectId(String projectId) { + if (diskType == null || diskType.project() != null) { + return this; + } + return toBuilder().diskType(diskType.setProjectId(projectId)).build(); + } + + @Override + com.google.api.services.compute.model.AttachedDisk toPb() { + com.google.api.services.compute.model.AttachedDisk attachedDiskPb = super.toPb(); + AttachedDiskInitializeParams initializeParamsPb = new AttachedDiskInitializeParams(); + if (diskType() != null) { + initializeParamsPb.setDiskType(diskType.selfLink()); + } + attachedDiskPb.setInitializeParams(initializeParamsPb); + return attachedDiskPb; + } + + /** + * Returns a builder for {@code ScratchAttachedDisk} objects given the disk type identity. + */ + public static Builder builder(DiskTypeId diskType) { + return new Builder(diskType); + } + + /** + * Returns a {@code ScratchAttachedDisk} object given the disk type identity. The disk will + * be attached via the default interface ({@link InterfaceType#SCSI}). + */ + public static ScratchAttachedDisk of(DiskTypeId diskType) { + return builder(diskType).build(); + } + + @SuppressWarnings("unchecked") + static ScratchAttachedDisk fromPb(com.google.api.services.compute.model.AttachedDisk diskPb) { + return new Builder(diskPb).build(); + } + } + + @SuppressWarnings("unchecked") + private AttachedDisk(Builder builder) { + this.deviceName = builder.deviceName; + this.index = builder.index; + this.licenses = (List) builder.licenses; + this.type = builder.type; + this.interfaceType = builder.interfaceType; + this.boot = builder.boot; + this.autoDelete = builder.autoDelete; + this.mode = builder.mode; + } + + /** + * Returns the unique device name of your choice that is reflected into the + * {@code /dev/disk/by-id/google-*} tree of a Linux operating system running within the + * instance. This name can be used to reference the device for mounting, resizing, and so on, + * from within the instance. If not specified, the service chooses a default device name to + * apply to this disk, in the form {@code persistent-disks-x}, where x is a number assigned by + * Google Compute Engine. + */ + public String deviceName() { + return deviceName; + } + + /** + * Returns a zero-based index to this disk, where 0 is reserved for the boot disk. + */ + public Integer index() { + return index; + } + + /** + * Returns a list of publicly accessible licenses. + */ + public List licenses() { + return licenses; + } + + /** + * Returns the type of the attached disk. + */ + public Type type() { + return type; + } + + /** + * Returns the interface to use to attach the disk. If not specified, {@link InterfaceType#SCSI} + * is used. + */ + public InterfaceType interfaceType() { + return interfaceType; + } + + /** + * Returns whether to use the attached disk as a boot disk. If {@code true} the virtual machine + * will use the first partition of the disk for its root filesystem. If not specified, the + * disk is not bootable. + */ + public Boolean boot() { + return boot; + } + + /** + * Returns whether the disk should auto-delete when the instance to which it's attached is + * deleted. If not specified, the disk is not deleted automatically. + */ + public Boolean autoDelete() { + return autoDelete; + } + + /** + * Returns the mode in which to attach this disk. If not specified, the disk is attached in + * {@link Mode#READ_WRITE} mode. + */ + public Mode mode() { + return mode; + } + + /** + * Returns a builder for the current attached disk. + */ + public abstract Builder toBuilder(); + + MoreObjects.ToStringHelper toStringHelper() { + return MoreObjects.toStringHelper(this) + .add("deviceName", deviceName) + .add("index", index) + .add("licenses", licenses) + .add("type", type) + .add("interfaceType", interfaceType) + .add("boot", boot) + .add("autoDelete", autoDelete) + .add("mode", mode); + } + + @Override + public String toString() { + return toStringHelper().toString(); + } + + final int baseHashCode() { + return Objects.hash(deviceName, index, licenses, type, interfaceType, boot, autoDelete, mode); + } + + final boolean baseEquals(AttachedDisk diskConfiguration) { + return Objects.equals(toPb(), diskConfiguration.toPb()); + } + + abstract AttachedDisk setProjectId(String projectId); + + com.google.api.services.compute.model.AttachedDisk toPb() { + com.google.api.services.compute.model.AttachedDisk attachedDiskPb = + new com.google.api.services.compute.model.AttachedDisk(); + attachedDiskPb.setDeviceName(deviceName); + attachedDiskPb.setIndex(index); + if (licenses != null) { + attachedDiskPb.setLicenses(Lists.transform(licenses, LicenseId.TO_URL_FUNCTION)); + } + attachedDiskPb.setType(type.toString()); + if (interfaceType != null) { + attachedDiskPb.setInterface(interfaceType.toString()); + } + attachedDiskPb.setBoot(boot); + attachedDiskPb.setAutoDelete(autoDelete); + if (mode != null) { + attachedDiskPb.setMode(mode.toString()); + } + return attachedDiskPb; + } + + @SuppressWarnings("unchecked") + static T fromPb( + com.google.api.services.compute.model.AttachedDisk diskPb) { + switch (Type.valueOf(diskPb.getType())) { + case PERSISTENT: + if (diskPb.getSource() == null) { + return (T) CreateAttachedDisk.fromPb(diskPb); + } else { + return (T) PersistentAttachedDisk.fromPb(diskPb); + } + case SCRATCH: + return (T) ScratchAttachedDisk.fromPb(diskPb); + default: + // should be unreachable + throw new IllegalArgumentException("Unrecognized attached disk type"); + } + } +} diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/AttachedDiskTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/AttachedDiskTest.java new file mode 100644 index 000000000000..ef4cc720f3a5 --- /dev/null +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/AttachedDiskTest.java @@ -0,0 +1,240 @@ +/* + * 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.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import com.google.common.collect.ImmutableList; +import com.google.gcloud.compute.AttachedDisk.CreateAttachedDisk; +import com.google.gcloud.compute.AttachedDisk.InterfaceType; +import com.google.gcloud.compute.AttachedDisk.Mode; +import com.google.gcloud.compute.AttachedDisk.PersistentAttachedDisk; +import com.google.gcloud.compute.AttachedDisk.ScratchAttachedDisk; +import com.google.gcloud.compute.AttachedDisk.Type; + +import org.junit.Test; + +import java.util.List; + +public class AttachedDiskTest { + + private static final Boolean AUTO_DELETE = true; + private static final Boolean BOOT = true; + private static final Integer INDEX = 0; + private static final String DEVICE_NAME = "deviceName"; + private static final String DISK_NAME = "diskName"; + private static final DiskTypeId DISK_TYPE_ID = DiskTypeId.of("project", "zone", "diskType"); + private static final Long DISK_SIZE_GB = 42L; + private static final DiskId DISK_ID = DiskId.of("project", "zone", "disk"); + private static final ImageId IMAGE_ID = ImageId.of("project", "image"); + private static final InterfaceType INTERFACE_TYPE = InterfaceType.NVME; + private static final Mode MODE = Mode.READ_ONLY; + private static final List LICENSES = ImmutableList.of( + LicenseId.of("project", "license1"), LicenseId.of("project", "license2")); + private static final PersistentAttachedDisk PERSISTENT_DISK = + PersistentAttachedDisk.builder(DISK_ID) + .deviceName(DEVICE_NAME) + .index(INDEX) + .licenses(LICENSES) + .boot(BOOT) + .autoDelete(AUTO_DELETE) + .mode(MODE) + .build(); + private static final ScratchAttachedDisk SCRATCH_DISK = + ScratchAttachedDisk.builder(DISK_TYPE_ID) + .deviceName(DEVICE_NAME) + .index(INDEX) + .licenses(LICENSES) + .interfaceType(INTERFACE_TYPE) + .build(); + private static final CreateAttachedDisk CREATED_DISK = CreateAttachedDisk.builder(IMAGE_ID) + .deviceName(DEVICE_NAME) + .index(INDEX) + .licenses(LICENSES) + .autoDelete(AUTO_DELETE) + .diskName(DISK_NAME) + .diskType(DISK_TYPE_ID) + .diskSizeGb(DISK_SIZE_GB) + .sourceImage(IMAGE_ID) + .build(); + + @Test + public void testToBuilder() { + compareAttachedDisk(PERSISTENT_DISK, PERSISTENT_DISK.toBuilder().build()); + compareAttachedDisk(SCRATCH_DISK, SCRATCH_DISK.toBuilder().build()); + compareAttachedDisk(CREATED_DISK, CREATED_DISK.toBuilder().build()); + AttachedDisk attachedDisk = PERSISTENT_DISK.toBuilder().deviceName("newDeviceName").build(); + assertEquals("newDeviceName", attachedDisk.deviceName()); + attachedDisk = attachedDisk.toBuilder().deviceName(DEVICE_NAME).build(); + compareAttachedDisk(PERSISTENT_DISK, attachedDisk); + } + + @Test + public void testToBuilderIncomplete() { + AttachedDisk attachedDisk = PersistentAttachedDisk.of(DISK_ID); + assertEquals(attachedDisk, attachedDisk.toBuilder().build()); + attachedDisk = ScratchAttachedDisk.of(DISK_TYPE_ID); + assertEquals(attachedDisk, attachedDisk.toBuilder().build()); + attachedDisk = CreateAttachedDisk.of(IMAGE_ID); + assertEquals(attachedDisk, attachedDisk.toBuilder().build()); + } + + @Test + public void testBuilder() { + assertEquals(BOOT, PERSISTENT_DISK.boot()); + assertEquals(AUTO_DELETE, PERSISTENT_DISK.autoDelete()); + assertNull(PERSISTENT_DISK.interfaceType()); + assertEquals(Type.PERSISTENT, PERSISTENT_DISK.type()); + assertEquals(MODE, PERSISTENT_DISK.mode()); + assertEquals(DISK_ID, PERSISTENT_DISK.sourceDisk()); + assertEquals(DEVICE_NAME, PERSISTENT_DISK.deviceName()); + assertEquals(INDEX, PERSISTENT_DISK.index()); + assertEquals(LICENSES, PERSISTENT_DISK.licenses()); + + assertFalse(SCRATCH_DISK.boot()); + assertTrue(SCRATCH_DISK.autoDelete()); + assertEquals(INTERFACE_TYPE, SCRATCH_DISK.interfaceType()); + assertEquals(Type.SCRATCH, SCRATCH_DISK.type()); + assertEquals(DISK_TYPE_ID, SCRATCH_DISK.diskType()); + assertEquals(DEVICE_NAME, SCRATCH_DISK.deviceName()); + assertEquals(INDEX, SCRATCH_DISK.index()); + assertEquals(LICENSES, SCRATCH_DISK.licenses()); + + assertTrue(CREATED_DISK.boot()); + assertEquals(AUTO_DELETE, CREATED_DISK.autoDelete()); + assertNull(CREATED_DISK.interfaceType()); + assertEquals(Type.PERSISTENT, CREATED_DISK.type()); + assertEquals(IMAGE_ID, CREATED_DISK.sourceImage()); + assertEquals(DISK_NAME, CREATED_DISK.diskName()); + assertEquals(DISK_TYPE_ID, CREATED_DISK.diskType()); + assertEquals(DISK_SIZE_GB, CREATED_DISK.diskSizeGb()); + assertEquals(DEVICE_NAME, CREATED_DISK.deviceName()); + assertEquals(INDEX, CREATED_DISK.index()); + assertEquals(LICENSES, CREATED_DISK.licenses()); + } + + @Test + public void testOf() { + PersistentAttachedDisk persistentAttachedDisk = PersistentAttachedDisk.of(DISK_ID); + assertNull(persistentAttachedDisk.boot()); + assertNull(persistentAttachedDisk.autoDelete()); + assertNull(persistentAttachedDisk.interfaceType()); + assertEquals(Type.PERSISTENT, persistentAttachedDisk.type()); + assertNull(persistentAttachedDisk.mode()); + assertEquals(DISK_ID, persistentAttachedDisk.sourceDisk()); + assertNull(persistentAttachedDisk.deviceName()); + assertNull(persistentAttachedDisk.index()); + assertNull(persistentAttachedDisk.licenses()); + + ScratchAttachedDisk scratchAttachedDisk = ScratchAttachedDisk.of(DISK_TYPE_ID); + assertFalse(scratchAttachedDisk.boot()); + assertTrue(scratchAttachedDisk.autoDelete()); + assertNull(scratchAttachedDisk.interfaceType()); + assertEquals(Type.SCRATCH, scratchAttachedDisk.type()); + assertEquals(DISK_TYPE_ID, scratchAttachedDisk.diskType()); + assertNull(scratchAttachedDisk.deviceName()); + assertNull(scratchAttachedDisk.index()); + assertNull(scratchAttachedDisk.licenses()); + + CreateAttachedDisk createAttachedDisk = CreateAttachedDisk.of(IMAGE_ID); + assertTrue(createAttachedDisk.boot()); + assertNull(createAttachedDisk.autoDelete()); + assertNull(createAttachedDisk.interfaceType()); + assertEquals(Type.PERSISTENT, createAttachedDisk.type()); + assertEquals(IMAGE_ID, createAttachedDisk.sourceImage()); + assertNull(createAttachedDisk.diskName()); + assertNull(createAttachedDisk.diskType()); + assertNull(createAttachedDisk.diskSizeGb()); + assertNull(createAttachedDisk.deviceName()); + assertNull(createAttachedDisk.index()); + assertNull(createAttachedDisk.licenses()); + } + + @Test + public void testToAndFromPb() { + AttachedDisk attachedDisk = AttachedDisk.fromPb(PERSISTENT_DISK.toPb()); + compareAttachedDisk(PERSISTENT_DISK, attachedDisk); + attachedDisk = AttachedDisk.fromPb(SCRATCH_DISK.toPb()); + compareAttachedDisk(SCRATCH_DISK, attachedDisk); + attachedDisk = AttachedDisk.fromPb(CREATED_DISK.toPb()); + compareAttachedDisk(CREATED_DISK, attachedDisk); + PersistentAttachedDisk persistentAttachedDisk = PersistentAttachedDisk.of(DISK_ID); + comparePersistentAttachedDisk(persistentAttachedDisk, + AttachedDisk.fromPb(persistentAttachedDisk.toPb())); + ScratchAttachedDisk scratchAttachedDisk = ScratchAttachedDisk.of(DISK_TYPE_ID); + compareScratchAttachedDisk(scratchAttachedDisk, + AttachedDisk.fromPb(scratchAttachedDisk.toPb())); + CreateAttachedDisk createAttachedDisk = CreateAttachedDisk.of(IMAGE_ID); + compareCreateAttachedDisk(createAttachedDisk, + AttachedDisk.fromPb(createAttachedDisk.toPb())); + } + + @Test + public void testSetProjectId() { + PersistentAttachedDisk persistentAttachedDisk = + PersistentAttachedDisk.of(DiskId.of("zone", "disk")); + comparePersistentAttachedDisk( + PersistentAttachedDisk.of(DiskId.of("project", "zone", "disk")), + persistentAttachedDisk.setProjectId("project")); + ScratchAttachedDisk scratchAttachedDisk = + ScratchAttachedDisk.of(DiskTypeId.of("zone", "diskType")); + compareScratchAttachedDisk( + ScratchAttachedDisk.of(DiskTypeId.of("project", "zone", "diskType")), + scratchAttachedDisk.setProjectId("project")); + CreateAttachedDisk createAttachedDisk = CREATED_DISK.toBuilder() + .diskType(DiskTypeId.of("zone", "diskType")) + .sourceImage(ImageId.of("image")) + .build(); + compareCreateAttachedDisk(CREATED_DISK, + createAttachedDisk.setProjectId("project")); + } + + public void comparePersistentAttachedDisk(PersistentAttachedDisk expected, + PersistentAttachedDisk value) { + compareAttachedDisk(expected, value); + assertEquals(expected.sourceDisk(), value.sourceDisk()); + } + + public void compareCreateAttachedDisk(CreateAttachedDisk expected, CreateAttachedDisk value) { + compareAttachedDisk(expected, value); + assertEquals(expected.diskName(), value.diskName()); + assertEquals(expected.diskType(), value.diskType()); + assertEquals(expected.diskSizeGb(), value.diskSizeGb()); + assertEquals(expected.sourceImage(), value.sourceImage()); + } + + public void compareScratchAttachedDisk(ScratchAttachedDisk expected, ScratchAttachedDisk value) { + compareAttachedDisk(expected, value); + assertEquals(expected.diskType(), value.diskType()); + } + + public void compareAttachedDisk(AttachedDisk expected, AttachedDisk value) { + assertEquals(expected, value); + assertEquals(expected.deviceName(), value.deviceName()); + assertEquals(expected.index(), value.index()); + assertEquals(expected.licenses(), value.licenses()); + assertEquals(expected.boot(), value.boot()); + assertEquals(expected.autoDelete(), value.autoDelete()); + assertEquals(expected.interfaceType(), value.interfaceType()); + assertEquals(expected.type(), value.type()); + assertEquals(expected.mode(), value.mode()); + 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 bec8844ae111..f8600f1cf395 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 @@ -22,6 +22,9 @@ import com.google.common.collect.ImmutableList; import com.google.gcloud.AuthCredentials; import com.google.gcloud.RetryParams; +import com.google.gcloud.compute.AttachedDisk.CreateAttachedDisk; +import com.google.gcloud.compute.AttachedDisk.PersistentAttachedDisk; +import com.google.gcloud.compute.AttachedDisk.ScratchAttachedDisk; import org.junit.Test; @@ -156,6 +159,12 @@ public class SerializationTest { private static final DiskInfo DISK_INFO = DiskInfo.of(DISK_ID, STANDARD_DISK_CONFIGURATION); private static final Disk DISK = new Disk.Builder(COMPUTE, DISK_ID, STANDARD_DISK_CONFIGURATION).build(); + private static final AttachedDisk PERSISTENT_ATTACHED_DISK = + PersistentAttachedDisk.of(DISK_ID); + private static final AttachedDisk SCRATCH_ATTACHED_DISK = + ScratchAttachedDisk.of(DISK_TYPE_ID); + private static final AttachedDisk CREATE_ATTACHED_DISK = + CreateAttachedDisk.of(IMAGE_ID); private static final Compute.DiskTypeOption DISK_TYPE_OPTION = Compute.DiskTypeOption.fields(); private static final Compute.DiskTypeFilter DISK_TYPE_FILTER = @@ -241,11 +250,12 @@ public void testModelAndRequests() throws Exception { ADDRESS_INFO, ADDRESS, DISK_ID, SNAPSHOT_ID, SNAPSHOT_INFO, SNAPSHOT, IMAGE_ID, DISK_IMAGE_CONFIGURATION, STORAGE_IMAGE_CONFIGURATION, IMAGE_INFO, IMAGE, STANDARD_DISK_CONFIGURATION, IMAGE_DISK_CONFIGURATION, SNAPSHOT_DISK_CONFIGURATION, - DISK_INFO, DISK, DISK_TYPE_OPTION, DISK_TYPE_FILTER, DISK_TYPE_LIST_OPTION, - DISK_TYPE_AGGREGATED_LIST_OPTION, MACHINE_TYPE_OPTION, MACHINE_TYPE_FILTER, - MACHINE_TYPE_LIST_OPTION, MACHINE_TYPE_AGGREGATED_LIST_OPTION, REGION_OPTION, REGION_FILTER, - REGION_LIST_OPTION, ZONE_OPTION, ZONE_FILTER, ZONE_LIST_OPTION, LICENSE_OPTION, - OPERATION_OPTION, OPERATION_FILTER, OPERATION_LIST_OPTION, ADDRESS_OPTION, ADDRESS_FILTER, + DISK_INFO, DISK, PERSISTENT_ATTACHED_DISK, SCRATCH_ATTACHED_DISK, CREATE_ATTACHED_DISK, + DISK_TYPE_OPTION, DISK_TYPE_FILTER, DISK_TYPE_LIST_OPTION, DISK_TYPE_AGGREGATED_LIST_OPTION, + MACHINE_TYPE_OPTION, MACHINE_TYPE_FILTER, MACHINE_TYPE_LIST_OPTION, + MACHINE_TYPE_AGGREGATED_LIST_OPTION, REGION_OPTION, REGION_FILTER, REGION_LIST_OPTION, + ZONE_OPTION, ZONE_FILTER, ZONE_LIST_OPTION, LICENSE_OPTION, OPERATION_OPTION, + OPERATION_FILTER, OPERATION_LIST_OPTION, ADDRESS_OPTION, ADDRESS_FILTER, ADDRESS_LIST_OPTION, ADDRESS_AGGREGATED_LIST_OPTION, SNAPSHOT_OPTION, SNAPSHOT_FILTER, SNAPSHOT_LIST_OPTION, IMAGE_OPTION, IMAGE_FILTER, IMAGE_LIST_OPTION, DISK_OPTION, DISK_FILTER, DISK_LIST_OPTION, DISK_AGGREGATED_LIST_OPTION};