/**
* 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 org.apache.aurora.scheduler.storage.db;
import java.util.Map;
import java.util.Optional;
import javax.inject.Inject;
import com.google.common.collect.Maps;
import org.apache.aurora.scheduler.storage.db.views.DBResourceAggregate;
import org.apache.aurora.scheduler.storage.db.views.DbTaskConfig;
import org.apache.aurora.scheduler.storage.entities.IAppcImage;
import org.apache.aurora.scheduler.storage.entities.IConstraint;
import org.apache.aurora.scheduler.storage.entities.IDockerContainer;
import org.apache.aurora.scheduler.storage.entities.IDockerImage;
import org.apache.aurora.scheduler.storage.entities.IImage;
import org.apache.aurora.scheduler.storage.entities.IMesosContainer;
import org.apache.aurora.scheduler.storage.entities.ITaskConfig;
import org.apache.aurora.scheduler.storage.entities.IValueConstraint;
import static java.util.Objects.requireNonNull;
class TaskConfigManager {
private final TaskConfigMapper configMapper;
private final JobKeyMapper jobKeyMapper;
@Inject
TaskConfigManager(TaskConfigMapper configMapper, JobKeyMapper jobKeyMapper) {
this.configMapper = requireNonNull(configMapper);
this.jobKeyMapper = requireNonNull(jobKeyMapper);
}
private Optional<Long> getConfigRow(ITaskConfig config) {
// NOTE: The 'config' object passed in MUST have all version-relevant fields populated in order
// to correctly compare with objects loaded from DB. This may not hold true if a 'config' is
// passed from storage recovery routine during version downgrade and fields are not properly
// backfilled. See AURORA-1603 for more details.
// We could optimize this slightly by first comparing the un-hydrated row and breaking early.
Map<ITaskConfig, DbTaskConfig> rowsByConfig =
Maps.uniqueIndex(
configMapper.selectConfigsByJob(config.getJob()),
DbTaskConfig::toImmutable);
return Optional.ofNullable(rowsByConfig.get(config)).map(DbTaskConfig::getRowId);
}
long insert(ITaskConfig config) {
InsertResult configInsert = new InsertResult();
// Determine whether this config is already stored.
Optional<Long> existingRow = getConfigRow(config);
if (existingRow.isPresent()) {
return existingRow.get();
}
jobKeyMapper.merge(config.getJob());
configMapper.insert(config, configInsert);
for (IConstraint constraint : config.getConstraints()) {
InsertResult constraintResult = new InsertResult();
configMapper.insertConstraint(configInsert.getId(), constraint, constraintResult);
switch (constraint.getConstraint().getSetField()) {
case VALUE:
IValueConstraint valueConstraint = constraint.getConstraint().getValue();
InsertResult valueResult = new InsertResult();
configMapper.insertValueConstraint(
constraintResult.getId(),
valueConstraint,
valueResult);
configMapper.insertValueConstraintValues(
valueResult.getId(),
valueConstraint.getValues());
break;
case LIMIT:
configMapper.insertLimitConstraint(
constraintResult.getId(),
constraint.getConstraint().getLimit());
break;
default:
throw new IllegalStateException(
"Unhandled constraint type " + constraint.getConstraint().getSetField());
}
}
if (!config.getResources().isEmpty()) {
configMapper.insertResources(
configInsert.getId(),
DBResourceAggregate.pairsFromResources(config.getResources()));
}
if (!config.getRequestedPorts().isEmpty()) {
configMapper.insertRequestedPorts(configInsert.getId(), config.getRequestedPorts());
}
if (!config.getTaskLinks().isEmpty()) {
configMapper.insertTaskLinks(configInsert.getId(), config.getTaskLinks());
}
if (!config.getMetadata().isEmpty()) {
configMapper.insertMetadata(configInsert.getId(), config.getMetadata());
}
if (!config.getMesosFetcherUris().isEmpty()) {
configMapper.insertMesosFetcherUris(configInsert.getId(), config.getMesosFetcherUris());
}
if (config.getContainer().isSetDocker()) {
IDockerContainer container = config.getContainer().getDocker();
InsertResult containerInsert = new InsertResult();
configMapper.insertContainer(configInsert.getId(), container, containerInsert);
if (!container.getParameters().isEmpty()) {
configMapper.insertDockerParameters(containerInsert.getId(), container.getParameters());
}
} else if (config.getContainer().isSetMesos()
&& config.getContainer().getMesos().isSetImage()) {
IMesosContainer container = config.getContainer().getMesos();
IImage image = container.getImage();
switch (image.getSetField()) {
case DOCKER:
IDockerImage dockerImage = image.getDocker();
configMapper.insertDockerImage(
configInsert.getId(),
dockerImage.getName(),
dockerImage.getTag());
break;
case APPC:
IAppcImage appcImage = image.getAppc();
configMapper.insertAppcImage(
configInsert.getId(),
appcImage.getName(),
appcImage.getImageId());
break;
default:
throw new IllegalStateException("Unexpected image type: " + image.getSetField());
}
if (!container.getVolumes().isEmpty()) {
configMapper.insertVolumes(configInsert.getId(), container.getVolumes());
}
}
return configInsert.getId();
}
}