package io.airlift.airship.agent; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.inject.Inject; import io.airlift.airship.shared.FileUtils; import io.airlift.airship.shared.Installation; import io.airlift.airship.shared.MavenCoordinates; import io.airlift.node.NodeInfo; import io.airlift.units.Duration; import javax.annotation.Nullable; import java.io.File; import java.util.List; import java.util.Set; import static io.airlift.airship.shared.FileUtils.listFiles; public class DirectoryDeploymentManagerFactory implements DeploymentManagerFactory { private final String location; private final Duration tarTimeout; private final File slotDir; @Inject public DirectoryDeploymentManagerFactory(NodeInfo nodeInfo, AgentConfig config) { this(nodeInfo.getLocation(), config.getSlotsDir(), config.getTarTimeout()); } public DirectoryDeploymentManagerFactory(String location, String slotsDir, Duration tarTimeout) { Preconditions.checkNotNull(location, "location is null"); Preconditions.checkNotNull(slotsDir, "slotsDir is null"); Preconditions.checkNotNull(tarTimeout, "tarTimeout is null"); this.location = location; this.tarTimeout = tarTimeout; this.slotDir = new File(slotsDir); slotDir.mkdirs(); if (!slotDir.isDirectory()) { throw new IllegalArgumentException("slotDir is not a directory: " + slotDir.getAbsolutePath()); } } @Override public List<DeploymentManager> loadSlots() { ImmutableList.Builder<DeploymentManager> builder = ImmutableList.builder(); for (File dir : listFiles(slotDir)) { if (dir.isDirectory() && new File(dir, "airship-slot-id.txt").canRead()) { DirectoryDeploymentManager deploymentManager = new DirectoryDeploymentManager(dir, location + "/" + dir.getName(), tarTimeout); builder.add(deploymentManager); } } return builder.build(); } @Override public DirectoryDeploymentManager createDeploymentManager(Installation installation) { File slotDirectory = getSlotDirectory(installation); return new DirectoryDeploymentManager(slotDirectory, location + "/" + slotDirectory.getName(), tarTimeout); } private synchronized File getSlotDirectory(Installation installation) { String baseName = toBaseName(installation); baseName = baseName.replace("[^a-zA-Z0-9_.-]", "_"); Set<String> fileNames = ImmutableSet.copyOf(Lists.transform(FileUtils.listFiles(slotDir), new Function<File, String>() { @Override public String apply(@Nullable File file) { return file.getName(); } })); if (!fileNames.contains(baseName)) { return new File(slotDir, baseName); } for (int i = 1; i < 10000; i++) { String directoryName = baseName + i; if (!fileNames.contains(directoryName)) { return new File(slotDir, directoryName); } } throw new IllegalStateException("Could not find an valid slot directory name"); } private String toBaseName(Installation installation) { String configSpec = installation.getAssignment().getConfig(); MavenCoordinates mavenCoordinates = MavenCoordinates.fromConfigGAV(configSpec); String baseName; if (mavenCoordinates != null) { baseName = mavenCoordinates.getArtifactId(); } else if (configSpec.startsWith("@")) { baseName = configSpec.substring(1); } else { baseName = configSpec; } return baseName; } }