package com.hubspot.singularity;
import static com.hubspot.singularity.JsonHelpers.copyOfList;
import static com.hubspot.singularity.JsonHelpers.copyOfMap;
import static com.hubspot.singularity.JsonHelpers.copyOfSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Optional;
import com.hubspot.deploy.ExecutorData;
import com.hubspot.deploy.HealthcheckOptions;
import com.hubspot.mesos.Resources;
import com.hubspot.mesos.SingularityContainerInfo;
import com.hubspot.mesos.SingularityMesosArtifact;
import com.hubspot.mesos.SingularityMesosTaskLabel;
import com.wordnik.swagger.annotations.ApiModelProperty;
public class SingularityDeploy {
private final String requestId;
private final String id;
private final Optional<String> version;
private final Optional<Long> timestamp;
private final Optional<Map<String, String>> metadata;
private final Optional<SingularityContainerInfo> containerInfo;
private final Optional<String> customExecutorCmd;
private final Optional<String> customExecutorId;
private final Optional<String> customExecutorSource;
private final Optional<Resources> customExecutorResources;
private final Optional<Resources> resources;
private final Optional<String> command;
private final Optional<List<String>> arguments;
private final Optional<Map<String, String>> env;
private final Optional<List<SingularityMesosArtifact>> uris;
private final Optional<ExecutorData> executorData;
private final Optional<Map<String, String>> labels;
private final Optional<List<SingularityMesosTaskLabel>> mesosLabels;
private final Optional<Map<Integer, Map<String, String>>> taskLabels;
private final Optional<Map<Integer, List<SingularityMesosTaskLabel>>> mesosTaskLabels;
private final Optional<Map<Integer, Map<String, String>>> taskEnv;
/**
* @deprecated use {@link #healthcheck}
*/
@Deprecated
private final Optional<String> healthcheckUri;
/**
* @deprecated use {@link #healthcheck}
*/
@Deprecated
private final Optional<Long> healthcheckIntervalSeconds;
/**
* @deprecated use {@link #healthcheck}
*/
@Deprecated
private final Optional<Long> healthcheckTimeoutSeconds;
/**
* @deprecated use {@link #healthcheck}
*/
@Deprecated
private final Optional<Integer> healthcheckPortIndex;
/**
* @deprecated use {@link #healthcheck}
*/
@Deprecated
private final Optional<HealthcheckProtocol> healthcheckProtocol;
/**
* @deprecated use {@link #healthcheck}
*/
@Deprecated
private final Optional<Integer> healthcheckMaxRetries;
/**
* @deprecated use {@link #healthcheck}
*/
@Deprecated
private final Optional<Long> healthcheckMaxTotalTimeoutSeconds;
private final Optional<HealthcheckOptions> healthcheck;
private final Optional<Boolean> skipHealthchecksOnDeploy;
private final Optional<Long> deployHealthTimeoutSeconds;
private final Optional<Long> considerHealthyAfterRunningForSeconds;
private final Optional<String> serviceBasePath;
private final Optional<Set<String>> loadBalancerGroups;
private final Optional<Integer> loadBalancerPortIndex;
private final Optional<Map<String, Object>> loadBalancerOptions;
private final Optional<Set<String>> loadBalancerDomains;
private final Optional<List<String>> loadBalancerAdditionalRoutes;
private final Optional<String> loadBalancerTemplate;
private final Optional<String> loadBalancerServiceIdOverride;
private final Optional<String> loadBalancerUpstreamGroup;
private final Optional<Integer> deployInstanceCountPerStep;
private final Optional<Integer> deployStepWaitTimeMs;
private final Optional<Boolean> autoAdvanceDeploySteps;
private final Optional<Integer> maxTaskRetries;
private final Optional<Boolean> shell;
private final Optional<String> user;
public static SingularityDeployBuilder newBuilder(String requestId, String id) {
return new SingularityDeployBuilder(requestId, id);
}
@JsonCreator
public SingularityDeploy(@JsonProperty("requestId") String requestId,
@JsonProperty("id") String id,
@JsonProperty("command") Optional<String> command,
@JsonProperty("arguments") Optional<List<String>> arguments,
@JsonProperty("containerInfo") Optional<SingularityContainerInfo> containerInfo,
@JsonProperty("customExecutorCmd") Optional<String> customExecutorCmd,
@JsonProperty("customExecutorId") Optional<String> customExecutorId,
@JsonProperty("customExecutorSource") Optional<String> customExecutorSource,
@JsonProperty("customExecutorResources") Optional<Resources> customExecutorResources,
@JsonProperty("resources") Optional<Resources> resources,
@JsonProperty("env") Optional<Map<String, String>> env,
@JsonProperty("taskEnv") Optional<Map<Integer, Map<String, String>>> taskEnv,
@JsonProperty("uris") Optional<List<SingularityMesosArtifact>> uris,
@JsonProperty("metadata") Optional<Map<String, String>> metadata,
@JsonProperty("executorData") Optional<ExecutorData> executorData,
@JsonProperty("version") Optional<String> version,
@JsonProperty("timestamp") Optional<Long> timestamp,
@JsonProperty("labels") Optional<Map<String, String>> labels,
@JsonProperty("mesosLabels") Optional<List<SingularityMesosTaskLabel>> mesosLabels,
@JsonProperty("taskLabels") Optional<Map<Integer, Map<String, String>>> taskLabels,
@JsonProperty("mesosTaskLabels") Optional<Map<Integer, List<SingularityMesosTaskLabel>>> mesosTaskLabels,
@JsonProperty("deployHealthTimeoutSeconds") Optional<Long> deployHealthTimeoutSeconds,
@JsonProperty("healthcheckUri") Optional<String> healthcheckUri,
@JsonProperty("healthcheckIntervalSeconds") Optional<Long> healthcheckIntervalSeconds,
@JsonProperty("healthcheckTimeoutSeconds") Optional<Long> healthcheckTimeoutSeconds,
@JsonProperty("healthcheckPortIndex") Optional<Integer> healthcheckPortIndex,
@JsonProperty("healthcheckMaxRetries") Optional<Integer> healthcheckMaxRetries,
@JsonProperty("healthcheckMaxTotalTimeoutSeconds") Optional<Long> healthcheckMaxTotalTimeoutSeconds,
@JsonProperty("healthcheck") Optional<HealthcheckOptions> healthcheck,
@JsonProperty("serviceBasePath") Optional<String> serviceBasePath,
@JsonProperty("loadBalancerGroups") Optional<Set<String>> loadBalancerGroups,
@JsonProperty("loadBalancerPortIndex") Optional<Integer> loadBalancerPortIndex,
@JsonProperty("considerHealthyAfterRunningForSeconds") Optional<Long> considerHealthyAfterRunningForSeconds,
@JsonProperty("loadBalancerOptions") Optional<Map<String, Object>> loadBalancerOptions,
@JsonProperty("loadBalancerDomains") Optional<Set<String>> loadBalancerDomains,
@JsonProperty("loadBalancerAdditionalRoutes") Optional<List<String>> loadBalancerAdditionalRoutes,
@JsonProperty("loadBalancerTemplate") Optional<String> loadBalancerTemplate,
@JsonProperty("loadBalancerServiceIdOverride") Optional<String> loadBalancerServiceIdOverride,
@JsonProperty("loadBalancerUpstreamGroup") Optional<String> loadBalancerUpstreamGroup,
@JsonProperty("skipHealthchecksOnDeploy") Optional<Boolean> skipHealthchecksOnDeploy,
@JsonProperty("healthCheckProtocol") Optional<HealthcheckProtocol> healthcheckProtocol,
@JsonProperty("deployInstanceCountPerStep") Optional<Integer> deployInstanceCountPerStep,
@JsonProperty("deployStepWaitTimeMs") Optional<Integer> deployStepWaitTimeMs,
@JsonProperty("autoAdvanceDeploySteps") Optional<Boolean> autoAdvanceDeploySteps,
@JsonProperty("maxTaskRetries") Optional<Integer> maxTaskRetries,
@JsonProperty("shell") Optional<Boolean> shell,
@JsonProperty("user") Optional<String> user) {
this.requestId = requestId;
this.command = command;
this.arguments = arguments;
this.resources = resources;
this.containerInfo = containerInfo;
this.customExecutorCmd = customExecutorCmd;
this.customExecutorId = customExecutorId;
this.customExecutorSource = customExecutorSource;
this.customExecutorResources = customExecutorResources;
this.metadata = metadata;
this.version = version;
this.id = id;
this.timestamp = timestamp;
this.env = env;
this.taskEnv = taskEnv;
this.uris = uris;
this.executorData = executorData;
this.labels = labels;
this.mesosLabels = mesosLabels.or(labels.isPresent() ? Optional.of(SingularityMesosTaskLabel.labelsFromMap(labels.get())) : Optional.<List<SingularityMesosTaskLabel>>absent());
this.taskLabels = taskLabels;
this.mesosTaskLabels = mesosTaskLabels.or(taskLabels.isPresent() ? Optional.of(parseMesosTaskLabelsFromMap(taskLabels.get())) : Optional.<Map<Integer,List<SingularityMesosTaskLabel>>>absent());
this.healthcheckUri = healthcheckUri;
this.healthcheckIntervalSeconds = healthcheckIntervalSeconds;
this.healthcheckTimeoutSeconds = healthcheckTimeoutSeconds;
this.healthcheckPortIndex = healthcheckPortIndex;
this.skipHealthchecksOnDeploy = skipHealthchecksOnDeploy;
this.healthcheckProtocol = healthcheckProtocol;
this.healthcheckMaxRetries = healthcheckMaxRetries;
this.healthcheckMaxTotalTimeoutSeconds = healthcheckMaxTotalTimeoutSeconds;
if (healthcheckUri.isPresent() && !healthcheck.isPresent()) {
this.healthcheck = Optional.of(new HealthcheckOptions(
healthcheckUri.get(),
healthcheckPortIndex,
Optional.<Long>absent(),
healthcheckProtocol,
Optional.<Integer>absent(),
Optional.<Integer>absent(),
Optional.<Integer>absent(),
healthcheckIntervalSeconds.isPresent() ? Optional.of(healthcheckIntervalSeconds.get().intValue()) : Optional.<Integer>absent(),
healthcheckTimeoutSeconds.isPresent() ? Optional.of(healthcheckTimeoutSeconds.get().intValue()) : Optional.<Integer>absent(),
healthcheckMaxRetries,
Optional.<List<Integer>>absent()));
} else {
this.healthcheck = healthcheck;
}
this.considerHealthyAfterRunningForSeconds = considerHealthyAfterRunningForSeconds;
this.deployHealthTimeoutSeconds = deployHealthTimeoutSeconds;
this.serviceBasePath = serviceBasePath;
this.loadBalancerGroups = loadBalancerGroups;
this.loadBalancerPortIndex = loadBalancerPortIndex;
this.loadBalancerOptions = loadBalancerOptions;
this.loadBalancerDomains = loadBalancerDomains;
this.loadBalancerAdditionalRoutes = loadBalancerAdditionalRoutes;
this.loadBalancerTemplate = loadBalancerTemplate;
this.loadBalancerServiceIdOverride = loadBalancerServiceIdOverride;
this.loadBalancerUpstreamGroup = loadBalancerUpstreamGroup;
this.deployInstanceCountPerStep = deployInstanceCountPerStep;
this.deployStepWaitTimeMs = deployStepWaitTimeMs;
this.autoAdvanceDeploySteps = autoAdvanceDeploySteps;
this.maxTaskRetries = maxTaskRetries;
this.shell = shell;
this.user = user;
}
private static Map<Integer, List<SingularityMesosTaskLabel>> parseMesosTaskLabelsFromMap(Map<Integer, Map<String, String>> taskLabels) {
Map<Integer, List<SingularityMesosTaskLabel>> mesosTaskLabels = new HashMap<>();
for (Map.Entry<Integer, Map<String, String>> entry : taskLabels.entrySet()) {
mesosTaskLabels.put(entry.getKey(), SingularityMesosTaskLabel.labelsFromMap(entry.getValue()));
}
return mesosTaskLabels;
}
public SingularityDeployBuilder toBuilder() {
return new SingularityDeployBuilder(requestId, id)
.setCommand(command)
.setArguments(copyOfList(arguments))
.setResources(resources)
.setContainerInfo(containerInfo)
.setCustomExecutorCmd(customExecutorCmd)
.setCustomExecutorId(customExecutorId)
.setCustomExecutorSource(customExecutorSource)
.setCustomExecutorResources(customExecutorResources)
.setHealthcheckUri(healthcheckUri)
.setHealthcheckIntervalSeconds(healthcheckIntervalSeconds)
.setHealthcheckTimeoutSeconds(healthcheckTimeoutSeconds)
.setHealthcheckPortIndex(healthcheckPortIndex)
.setSkipHealthchecksOnDeploy(skipHealthchecksOnDeploy)
.setHealthcheckProtocol(healthcheckProtocol)
.setHealthcheckMaxRetries(healthcheckMaxRetries)
.setHealthcheckMaxTotalTimeoutSeconds(healthcheckMaxTotalTimeoutSeconds)
.setHealthcheck(healthcheck)
.setConsiderHealthyAfterRunningForSeconds(considerHealthyAfterRunningForSeconds)
.setDeployHealthTimeoutSeconds(deployHealthTimeoutSeconds)
.setServiceBasePath(serviceBasePath)
.setLoadBalancerGroups(copyOfSet(loadBalancerGroups))
.setLoadBalancerPortIndex(loadBalancerPortIndex)
.setLoadBalancerOptions(copyOfMap(loadBalancerOptions))
.setLoadBalancerDomains(copyOfSet(loadBalancerDomains))
.setLoadBalancerAdditionalRoutes(copyOfList(loadBalancerAdditionalRoutes))
.setLoadBalancerTemplate(loadBalancerTemplate)
.setLoadBalancerUpstreamGroup(loadBalancerUpstreamGroup)
.setLoadBalancerServiceIdOverride(loadBalancerServiceIdOverride)
.setMetadata(copyOfMap(metadata))
.setVersion(version)
.setTimestamp(timestamp)
.setEnv(copyOfMap(env))
.setTaskEnv(taskEnv)
.setUris(uris)
.setExecutorData(executorData)
.setLabels(labels)
.setMesosLabels(mesosLabels)
.setTaskLabels(taskLabels)
.setMesosTaskLabels(mesosTaskLabels)
.setDeployInstanceCountPerStep(deployInstanceCountPerStep)
.setDeployStepWaitTimeMs(deployStepWaitTimeMs)
.setAutoAdvanceDeploySteps(autoAdvanceDeploySteps)
.setMaxTaskRetries(maxTaskRetries)
.setShell(shell)
.setUser(user);
}
@ApiModelProperty(required=false, value="Number of seconds that Singularity waits for this service to become healthy (for it to download artifacts, start running, and optionally pass healthchecks.)")
public Optional<Long> getDeployHealthTimeoutSeconds() {
return deployHealthTimeoutSeconds;
}
@ApiModelProperty(required=true, value="Singularity Request Id which is associated with this deploy.")
public String getRequestId() {
return requestId;
}
@ApiModelProperty(required=true, value="Singularity deploy id.")
public String getId() {
return id;
}
@ApiModelProperty(required=false, value="Deploy version")
public Optional<String> getVersion() {
return version;
}
@ApiModelProperty(required=false, value="Deploy timestamp.")
public Optional<Long> getTimestamp() {
return timestamp;
}
@ApiModelProperty(required=false, value="Map of metadata key/value pairs associated with the deployment.")
public Optional<Map<String, String>> getMetadata() {
return metadata;
}
@ApiModelProperty(required=false, value="Container information for deployment into a container.", dataType="SingularityContainerInfo")
public Optional<SingularityContainerInfo> getContainerInfo() {
return containerInfo;
}
@ApiModelProperty(required=false, value="Custom Mesos executor", dataType="string")
public Optional<String> getCustomExecutorCmd() {
return customExecutorCmd;
}
@ApiModelProperty(required=false, value="Custom Mesos executor id.", dataType="string")
public Optional<String> getCustomExecutorId() {
return customExecutorId;
}
@ApiModelProperty(required=false, value="Custom Mesos executor source.", dataType="string")
public Optional<String> getCustomExecutorSource() { return customExecutorSource; }
@ApiModelProperty(required=false, value="Resources to allocate for custom mesos executor", dataType="com.hubspot.mesos.Resources")
public Optional<Resources> getCustomExecutorResources() {
return customExecutorResources;
}
@ApiModelProperty(required=false, value="Resources required for this deploy.", dataType="com.hubspot.mesos.Resources")
public Optional<Resources> getResources() {
return resources;
}
@ApiModelProperty(required=false, value="Command to execute for this deployment.")
public Optional<String> getCommand() {
return command;
}
@ApiModelProperty(required=false, value="Command arguments.")
public Optional<List<String>> getArguments() {
return arguments;
}
@ApiModelProperty(required=false, value="Map of environment variable definitions.")
public Optional<Map<String, String>> getEnv() {
return env;
}
@ApiModelProperty(required=false, value="Map of environment variable overrides for specific task instances.")
public Optional<Map<Integer, Map<String, String>>> getTaskEnv() {
return taskEnv;
}
@ApiModelProperty(required=false, value="List of URIs to download before executing the deploy command.")
public Optional<List<SingularityMesosArtifact>> getUris() {
return uris;
}
@ApiModelProperty(required=false, value="Executor specific information")
public Optional<ExecutorData> getExecutorData() {
return executorData;
}
@ApiModelProperty(required=false, value="Deployment Healthcheck URI, if specified will be called after TASK_RUNNING.")
public Optional<String> getHealthcheckUri() {
return healthcheckUri;
}
@ApiModelProperty(required=false, value="Healthcheck protocol - HTTP or HTTPS", dataType="com.hubspot.singularity.HealthcheckProtocol")
public Optional<HealthcheckProtocol> getHealthcheckProtocol() {
return healthcheckProtocol;
}
@ApiModelProperty(required=false, value="Time to wait after a failed healthcheck to try again in seconds.")
public Optional<Long> getHealthcheckIntervalSeconds() {
return healthcheckIntervalSeconds;
}
@ApiModelProperty(required=false, value="Single healthcheck HTTP timeout in seconds.")
public Optional<Long> getHealthcheckTimeoutSeconds() {
return healthcheckTimeoutSeconds;
}
@ApiModelProperty(required=false, value="Perform healthcheck on this dynamically allocated port (e.g. 0 for first port), defaults to first port")
public Optional<Integer> getHealthcheckPortIndex() {
return healthcheckPortIndex;
}
@ApiModelProperty(required=false, value="The base path for the API exposed by the deploy. Used in conjunction with the Load balancer API.")
public Optional<String> getServiceBasePath() {
return serviceBasePath;
}
@ApiModelProperty(required=false, value="Number of seconds that a service must be healthy to consider the deployment to be successful.")
public Optional<Long> getConsiderHealthyAfterRunningForSeconds() {
return considerHealthyAfterRunningForSeconds;
}
@ApiModelProperty(required=false, value="List of load balancer groups associated with this deployment.")
public Optional<Set<String>> getLoadBalancerGroups() {
return loadBalancerGroups;
}
@ApiModelProperty(required=false, value="Send this port to the load balancer api (e.g. 0 for first port), defaults to first port")
public Optional<Integer> getLoadBalancerPortIndex() {
return loadBalancerPortIndex;
}
@ApiModelProperty(required=false, value="Map (Key/Value) of options for the load balancer.")
public Optional<Map<String, Object>> getLoadBalancerOptions() {
return loadBalancerOptions;
}
@ApiModelProperty(required=false, value="List of domains to host this service on, for use with the load balancer api")
public Optional<Set<String>> getLoadBalancerDomains() {
return loadBalancerDomains;
}
@ApiModelProperty(required=false, value="Additional routes besides serviceBasePath used by this service")
public Optional<List<String>> getLoadBalancerAdditionalRoutes() {
return loadBalancerAdditionalRoutes;
}
@ApiModelProperty(required=false, value="Name of load balancer template to use if not using the default template")
public Optional<String> getLoadBalancerTemplate() {
return loadBalancerTemplate;
}
@ApiModelProperty(required=false, value="Name of load balancer Service ID to use instead of the Request ID")
public Optional<String> getLoadBalancerServiceIdOverride() {
return loadBalancerServiceIdOverride;
}
@ApiModelProperty(required=false, value="Group name to tag all upstreams with in load balancer")
public Optional<String> getLoadBalancerUpstreamGroup() {
return loadBalancerUpstreamGroup;
}
@Deprecated
@ApiModelProperty(required=false, value="Labels for all tasks associated with this deploy")
public Optional<Map<String, String>> getLabels() {
return labels;
}
@ApiModelProperty(required=false, value="Labels for all tasks associated with this deploy")
public Optional<List<SingularityMesosTaskLabel>> getMesosLabels() {
return mesosLabels;
}
@ApiModelProperty(required=false, value="(Deprecated) Labels for specific tasks associated with this deploy, indexed by instance number")
public Optional<Map<Integer, Map<String, String>>> getTaskLabels() {
return taskLabels;
}
@ApiModelProperty(required=false, value="Labels for specific tasks associated with this deploy, indexed by instance number")
public Optional<Map<Integer, List<SingularityMesosTaskLabel>>> getMesosTaskLabels() {
return mesosTaskLabels;
}
@ApiModelProperty(required=false, value="Allows skipping of health checks when deploying.")
public Optional<Boolean> getSkipHealthchecksOnDeploy() {
return skipHealthchecksOnDeploy;
}
@ApiModelProperty(required=false, value="Maximum number of times to retry an individual healthcheck before failing the deploy.")
public Optional<Integer> getHealthcheckMaxRetries() {
return healthcheckMaxRetries;
}
@ApiModelProperty(required=false, value="Maximum amount of time to wait before failing a deploy for healthchecks to pass.")
public Optional<Long> getHealthcheckMaxTotalTimeoutSeconds() {
return healthcheckMaxTotalTimeoutSeconds;
}
@ApiModelProperty(required = false, value="HTTP Healthcheck settings")
public Optional<HealthcheckOptions> getHealthcheck() {
return healthcheck;
}
@ApiModelProperty(required=false, value="deploy this many instances at a time")
public Optional<Integer> getDeployInstanceCountPerStep() {
return deployInstanceCountPerStep;
}
@ApiModelProperty(required=false, value="wait this long between deploy steps")
public Optional<Integer> getDeployStepWaitTimeMs() {
return deployStepWaitTimeMs;
}
@ApiModelProperty(required=false, value="automatically advance to the next target instance count after `deployStepWaitTimeMs` seconds")
public Optional<Boolean> getAutoAdvanceDeploySteps() {
return autoAdvanceDeploySteps;
}
@ApiModelProperty(required=false, value="allowed at most this many failed tasks to be retried before failing the deploy")
public Optional<Integer> getMaxTaskRetries() {
return maxTaskRetries;
}
@ApiModelProperty(required=false, value="Override the shell property on the mesos task")
public Optional<Boolean> getShell() {
return shell;
}
@ApiModelProperty(required=false, value="Run tasks as this user")
public Optional<String> getUser() {
return user;
}
@Override
public String toString() {
return "SingularityDeploy{" +
"requestId='" + requestId + '\'' +
", id='" + id + '\'' +
", version=" + version +
", timestamp=" + timestamp +
", metadata=" + metadata +
", containerInfo=" + containerInfo +
", customExecutorCmd=" + customExecutorCmd +
", customExecutorId=" + customExecutorId +
", customExecutorSource=" + customExecutorSource +
", customExecutorResources=" + customExecutorResources +
", resources=" + resources +
", command=" + command +
", arguments=" + arguments +
", env=" + env +
", uris=" + uris +
", executorData=" + executorData +
", labels=" + labels +
", mesosLabels=" + mesosLabels +
", taskLabels=" + taskLabels +
", mesosTaskLabels=" + mesosTaskLabels +
", taskEnv=" + taskEnv +
", healthcheckUri=" + healthcheckUri +
", healthcheckIntervalSeconds=" + healthcheckIntervalSeconds +
", healthcheckTimeoutSeconds=" + healthcheckTimeoutSeconds +
", healthcheckPortIndex=" + healthcheckPortIndex +
", healthcheckProtocol=" + healthcheckProtocol +
", healthcheckMaxRetries=" + healthcheckMaxRetries +
", healthcheckMaxTotalTimeoutSeconds=" + healthcheckMaxTotalTimeoutSeconds +
", healthcheck=" + healthcheck +
", skipHealthchecksOnDeploy=" + skipHealthchecksOnDeploy +
", deployHealthTimeoutSeconds=" + deployHealthTimeoutSeconds +
", considerHealthyAfterRunningForSeconds=" + considerHealthyAfterRunningForSeconds +
", serviceBasePath=" + serviceBasePath +
", loadBalancerGroups=" + loadBalancerGroups +
", loadBalancerPortIndex=" + loadBalancerPortIndex +
", loadBalancerOptions=" + loadBalancerOptions +
", loadBalancerDomains=" + loadBalancerDomains +
", loadBalancerAdditionalRoutes=" + loadBalancerAdditionalRoutes +
", loadBalancerTemplate=" + loadBalancerTemplate +
", loadBalancerServiceIdOverride=" + loadBalancerServiceIdOverride +
", loadBalancerUpstreamGroup=" + loadBalancerUpstreamGroup +
", deployInstanceCountPerStep=" + deployInstanceCountPerStep +
", deployStepWaitTimeMs=" + deployStepWaitTimeMs +
", autoAdvanceDeploySteps=" + autoAdvanceDeploySteps +
", maxTaskRetries=" + maxTaskRetries +
", shell=" + shell +
", user=" + user +
'}';
}
}