java/com/google/cloud/deploymentmanager/autogen/SpecDefaults.java (245 lines of code) (raw):
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 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.cloud.deploymentmanager.autogen;
import com.google.cloud.deploymentmanager.autogen.proto.AcceleratorSpec;
import com.google.cloud.deploymentmanager.autogen.proto.ApplicationStatusSpec;
import com.google.cloud.deploymentmanager.autogen.proto.DeployInputField;
import com.google.cloud.deploymentmanager.autogen.proto.DeployInputField.TypeCase;
import com.google.cloud.deploymentmanager.autogen.proto.DeployInputSection;
import com.google.cloud.deploymentmanager.autogen.proto.DeployInputSpec;
import com.google.cloud.deploymentmanager.autogen.proto.DiskSpec;
import com.google.cloud.deploymentmanager.autogen.proto.DiskSpec.DeviceName;
import com.google.cloud.deploymentmanager.autogen.proto.ExternalIpSpec;
import com.google.cloud.deploymentmanager.autogen.proto.FirewallRuleSpec;
import com.google.cloud.deploymentmanager.autogen.proto.FirewallRuleSpec.TrafficSource;
import com.google.cloud.deploymentmanager.autogen.proto.MachineTypeSpec;
import com.google.cloud.deploymentmanager.autogen.proto.MachineTypeSpec.MachineType;
import com.google.cloud.deploymentmanager.autogen.proto.MultiVmDeploymentPackageSpec;
import com.google.cloud.deploymentmanager.autogen.proto.MultiVmDeploymentPackageSpecOrBuilder;
import com.google.cloud.deploymentmanager.autogen.proto.NetworkInterfacesSpec;
import com.google.cloud.deploymentmanager.autogen.proto.PasswordSpec;
import com.google.cloud.deploymentmanager.autogen.proto.PostDeployInfo;
import com.google.cloud.deploymentmanager.autogen.proto.PostDeployInfo.ConnectToInstanceSpec;
import com.google.cloud.deploymentmanager.autogen.proto.SingleVmDeploymentPackageSpec;
import com.google.cloud.deploymentmanager.autogen.proto.TierVmInstance;
import com.google.cloud.deploymentmanager.autogen.proto.VmTierSpec;
import com.google.cloud.deploymentmanager.autogen.proto.VmTierSpec.TierInstanceCount;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import java.util.List;
/**
* Fills in missing fields with defaults where appropriate to make complete specs. Some required
* fields cannot use defaults--validations of such are in {@link SpecValidations}.
*
* @see SpecValidations
*/
final class SpecDefaults {
private static final String DEFAULT_MACHINE_TYPE = "e2-small";
private static final String DEFAULT_MACHINE_TYPE_GPU_SUPPORT = "e2-standard-2";
private static final int DEFAULT_BOOT_DISK_SIZE_GB = 10;
private static final String DEFAULT_BOOT_DISK_TYPE = "pd-standard";
private static final int DEFAULT_ADDITIONAL_DISK_SIZE_GB = 10;
private static final String DEFAULT_ADDITIONAL_DISK_TYPE = "pd-standard";
private static final String DEFAULT_PASSWORD_LABEL = "Admin";
private static final String DEFAULT_CONNECT_BUTTON_LABEL = "SSH";
private static final String DEFAULT_BOOT_DISK_DISPLAY_LABEL = "Boot disk";
private static final String DEFAULT_ADDITIONAL_DISK_DISPLAY_LABEL = "Data disk";
private static final String DEFAULT_INSTANCE_COUNT_RANGE_TOOLTIP =
"Specify a value between %d and %d.";
/**
* Fills in the default values for missing optional fields, and validates that the spec is
* reasonable, throwing {@link IllegalArgumentException} if not.
*/
public static SingleVmDeploymentPackageSpec.Builder fillInMissingDefaults(
SingleVmDeploymentPackageSpec.Builder input) {
setMachineTypeDefaults(
input.getMachineTypeBuilder(), !input.getAcceleratorsBuilderList().isEmpty());
setAceleratorsDefaults(input.getAcceleratorsBuilderList());
setBootDiskDefaults(input.getBootDiskBuilder());
setAdditionalDisksDefaults(input.getAdditionalDisksBuilderList());
setPasswordDefaults(input.getPasswordsBuilderList());
// We keep the external IP spec to be backwards compatible to old solutions. If present, we will
// set it as the default external IP spec of the NetworkInterfacesSpec
ExternalIpSpec deprecatedExternalIp = input.hasExternalIp() ? input.getExternalIp() : null;
setNetworkInterfacesDefault(input.getNetworkInterfacesBuilder(), deprecatedExternalIp);
if (input.hasApplicationStatus()) {
// Fill in defaults only when the application status is actually desired (i.e. set by user).
// Note that .get*Builder() will blindly set the field, so we need the if.
setApplicationStatusDefaults(input.getApplicationStatusBuilder());
}
setConnectButtonDefaults_singlevm(input.getPostDeployBuilder());
setDeployInputFieldsDefaults(input.getDeployInputBuilder());
setFirewallDefaults(input.getFirewallRulesBuilderList());
return input;
}
public static MultiVmDeploymentPackageSpec.Builder fillInMissingDefaults(
MultiVmDeploymentPackageSpec.Builder input) {
for (VmTierSpec.Builder tier : input.getTiersBuilderList()) {
setInstanceCountDefaults(tier.getInstanceCountBuilder());
setMachineTypeDefaults(
tier.getMachineTypeBuilder(), !tier.getAcceleratorsBuilderList().isEmpty());
setAceleratorsDefaults(tier.getAcceleratorsBuilderList());
setBootDiskDefaults(tier.getBootDiskBuilder());
setAdditionalDisksDefaults(tier.getAdditionalDisksBuilderList());
// We keep the external IP spec to be backwards compatible to old solutions. If present, we
// will set it as the default external IP spec of the NetworkInterfacesSpec
ExternalIpSpec deprecatedExternalIp = tier.hasExternalIp() ? tier.getExternalIp() : null;
setNetworkInterfacesDefault(tier.getNetworkInterfacesBuilder(), deprecatedExternalIp);
if (tier.hasApplicationStatus()) {
// Fill in defaults only when the application status is actually desired (i.e. set by user).
// Note that .get*Builder() will blindly set the field, so we need the if.
setApplicationStatusDefaults(tier.getApplicationStatusBuilder());
}
setFirewallDefaults(tier.getFirewallRulesBuilderList());
}
setPasswordDefaults(input.getPasswordsBuilderList());
setConnectButtonDefaults_multivm(input.getPostDeployBuilder(), input);
setDeployInputFieldsDefaults(input.getDeployInputBuilder());
return input;
}
private static void setConnectButtonDefaults_singlevm(PostDeployInfo.Builder postDeploy) {
setConnectButtonDefaults_common(postDeploy);
}
private static void setConnectButtonDefaults_multivm(PostDeployInfo.Builder postDeploy,
MultiVmDeploymentPackageSpecOrBuilder multiVmSpec) {
if (!postDeploy.hasConnectButton() && multiVmSpec.getTiersCount() > 1) {
return;
}
setConnectButtonDefaults_common(postDeploy);
ConnectToInstanceSpec.Builder connectButton = postDeploy.getConnectButtonBuilder();
// If connect button does not specify the vm instance, but the spec contains only one tier,
// use the first instance of this tier in the connect button.
if (!connectButton.hasTierVm() && multiVmSpec.getTiersCount() == 1) {
TierVmInstance tier = TierVmInstance.newBuilder()
.setTier(multiVmSpec.getTiers(0).getName())
.setIndex(0)
.build();
connectButton.setTierVm(tier);
}
}
private static void setConnectButtonDefaults_common(PostDeployInfo.Builder postDeploy) {
ConnectToInstanceSpec.Builder button = postDeploy.getConnectButtonBuilder();
if (Strings.isNullOrEmpty(button.getDisplayLabel())
&& Strings.isNullOrEmpty(postDeploy.getConnectButtonLabel())) {
// Ideally we should allow empty button label, in which case the widget should automatically
// determine the right label (SSH for Linux, RDP for Windows). We need to change the UI and
// config validation in order to support this. Once that happens, this default can be dropped.
button.setDisplayLabel(DEFAULT_CONNECT_BUTTON_LABEL);
}
// TODO(khajduczenia) The following copy action should be removed as soon as FE is migrated.
// Support for deprecated connect_button_label field in PostDeployInfo:
if (Strings.isNullOrEmpty(button.getDisplayLabel())
&& !Strings.isNullOrEmpty(postDeploy.getConnectButtonLabel())) {
button.setDisplayLabel(postDeploy.getConnectButtonLabel());
}
}
private static void setInstanceCountDefaults(TierInstanceCount.Builder input) {
if (Strings.isNullOrEmpty(input.getTooltip()) && input.hasRange()) {
String tooltip = String.format(DEFAULT_INSTANCE_COUNT_RANGE_TOOLTIP,
input.getRange().getStartValue(),
input.getRange().getEndValue());
input.setTooltip(tooltip);
}
}
private static void setNetworkInterfacesDefault(
NetworkInterfacesSpec.Builder input, ExternalIpSpec deprecatedExternalIp) {
if (input.getMinCount() < 1) {
input.setMinCount(1);
}
if (input.getMaxCount() < 1) {
input.setMaxCount(input.getMinCount());
}
if (!input.hasExternalIp() && deprecatedExternalIp != null) {
input.setExternalIp(deprecatedExternalIp);
}
setExternalIpDefaults(input.getExternalIpBuilder());
}
private static void setMachineTypeDefaults(MachineTypeSpec.Builder input, boolean supportGpu) {
if (input.getDefaultMachineTypeOrBuilder().getGceMachineType().isEmpty()) {
input.setDefaultMachineType(
MachineType.newBuilder()
.setGceMachineType(
supportGpu ? DEFAULT_MACHINE_TYPE_GPU_SUPPORT : DEFAULT_MACHINE_TYPE));
}
}
private static void setAceleratorsDefaults(List<AcceleratorSpec.Builder> input) {
for (AcceleratorSpec.Builder accelerator : input) {
if (accelerator.getDefaultType().isEmpty()) {
accelerator.setDefaultType(accelerator.getTypes(0));
}
}
}
private static void setDiskSizeDefaults(DiskSpec.Builder input,
int defaultSizeGb, int defaultMinSizeGb) {
if (!input.hasDiskSize()) {
input.getDiskSizeBuilder()
.setDefaultSizeGb(defaultSizeGb)
.setMinSizeGb(defaultMinSizeGb);
}
}
private static void setDiskTypeDefaults(DiskSpec.Builder input, String defaultType) {
if (!input.hasDiskType()) {
input.getDiskTypeBuilder().setDefaultType(defaultType);
}
}
private static void setBootDiskDefaults(DiskSpec.Builder input) {
final int diskSizeGb = DEFAULT_BOOT_DISK_SIZE_GB;
setDiskSizeDefaults(input, diskSizeGb, diskSizeGb);
setDiskTypeDefaults(input, DEFAULT_BOOT_DISK_TYPE);
if (Strings.isNullOrEmpty(input.getDisplayLabel())) {
input.setDisplayLabel(DEFAULT_BOOT_DISK_DISPLAY_LABEL);
}
}
private static void setAdditionalDisksDefaults(List<DiskSpec.Builder> input) {
final int diskSizeGb = DEFAULT_ADDITIONAL_DISK_SIZE_GB;
int diskNumber = 1;
for (DiskSpec.Builder disk : input) {
setDiskSizeDefaults(disk, diskSizeGb, diskSizeGb);
setDiskTypeDefaults(disk, DEFAULT_ADDITIONAL_DISK_TYPE);
if (!disk.hasDeviceNameSuffix()) {
DeviceName name = DeviceName.newBuilder()
.setName("disk" + diskNumber)
.build();
disk.setDeviceNameSuffix(name);
}
diskNumber++;
}
if (input.size() == 1) {
DiskSpec.Builder firstDisk = input.get(0);
if (Strings.isNullOrEmpty(firstDisk.getDisplayLabel())) {
firstDisk.setDisplayLabel(DEFAULT_ADDITIONAL_DISK_DISPLAY_LABEL);
}
}
}
private static void setExternalIpDefaults(ExternalIpSpec.Builder input) {
if (input.getDefaultType().equals(ExternalIpSpec.Type.TYPE_UNSPECIFIED)) {
input.setDefaultType(ExternalIpSpec.Type.EPHEMERAL);
}
}
private static void setApplicationStatusDefaults(ApplicationStatusSpec.Builder input) {
if (input.hasWaiter()) {
ApplicationStatusSpec.WaiterSpec.Builder waiter = input.getWaiterBuilder();
if (waiter.hasScript() && waiter.getScript().getCheckTimeoutSecs() == 0) {
waiter.getScriptBuilder().setCheckTimeoutSecs(waiter.getWaiterTimeoutSecs());
}
}
}
private static void setPasswordDefaults(List<PasswordSpec.Builder> passwords) {
if (passwords.size() != 1) {
return;
}
PasswordSpec.Builder onlyPassword = Iterables.getOnlyElement(passwords);
if (onlyPassword.getDisplayLabel().isEmpty()) {
onlyPassword.setDisplayLabel(DEFAULT_PASSWORD_LABEL);
}
}
private static void setFirewallDefaults(List<FirewallRuleSpec.Builder> rules) {
for (FirewallRuleSpec.Builder rule : rules) {
if (rule.getAllowedSource().equals(TrafficSource.SOURCE_UNSPECIFIED)) {
rule.setAllowedSource(TrafficSource.PUBLIC);
}
}
}
private static void setDeployInputFieldsDefaults(DeployInputSpec.Builder deployInput) {
for (DeployInputSection.Builder section : deployInput.getSectionsBuilderList()) {
for (DeployInputField.Builder field : section.getFieldsBuilderList()) {
if (field.getTypeCase() == TypeCase.EMAIL_BOX) {
setDeployInputFieldsDefaultsToEmailbox(field);
}
}
}
}
private static void setDeployInputFieldsDefaultsToEmailbox(DeployInputField.Builder field) {
if (field.getRequired()) {
// Override test_default_value, if is not present.
if (field.getEmailBox().getTestDefaultValue().isEmpty()) {
if (field.getEmailBox().getDefaultValue().isEmpty()) {
// Set default, if default_value is not present.
field.getEmailBoxBuilder().setTestDefaultValue("default-user@example.com");
} else {
// Use default_value property to override test_default_value.
field.getEmailBoxBuilder().setTestDefaultValue(field.getEmailBox().getDefaultValue());
}
}
}
if (field.getEmailBox().getPlaceholder().isEmpty()) {
field.getEmailBoxBuilder().setPlaceholder("user@example.com");
}
if (field.getEmailBox().getValidation().getDescription().isEmpty()) {
field.getEmailBoxBuilder()
.getValidationBuilder()
.setDescription("Please enter a valid email address");
}
}
private SpecDefaults() {}
}