/**
* 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 io.airlift.airship.agent;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Inject;
import io.airlift.airship.shared.AgentStatus;
import io.airlift.airship.shared.Installation;
import io.airlift.airship.shared.SlotStatus;
import io.airlift.http.server.HttpServerInfo;
import io.airlift.node.NodeInfo;
import io.airlift.units.Duration;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static io.airlift.airship.shared.AgentLifecycleState.ONLINE;
import static io.airlift.airship.shared.HttpUriBuilder.uriBuilderFrom;
import static io.airlift.airship.shared.SlotLifecycleState.TERMINATED;
import static java.lang.String.format;
public class Agent
{
private final String agentId;
private final ConcurrentMap<UUID, Slot> slots;
private final DeploymentManagerFactory deploymentManagerFactory;
private final LifecycleManager lifecycleManager;
private final String location;
private final Map<String, Integer> resources;
private final Duration maxLockWait;
private final URI internalUri;
private final URI externalUri;
@Inject
public Agent(AgentConfig config,
HttpServerInfo httpServerInfo,
NodeInfo nodeInfo,
DeploymentManagerFactory deploymentManagerFactory,
LifecycleManager lifecycleManager)
{
this(nodeInfo.getNodeId(),
nodeInfo.getLocation(),
config.getSlotsDir(),
httpServerInfo.getHttpUri(),
httpServerInfo.getHttpExternalUri(),
config.getResourcesFile(),
deploymentManagerFactory,
lifecycleManager,
config.getMaxLockWait()
);
}
public Agent(
String agentId,
String location,
String slotsDirName,
URI internalUri,
URI externalUri,
String resourcesFilename,
DeploymentManagerFactory deploymentManagerFactory,
LifecycleManager lifecycleManager,
Duration maxLockWait)
{
Preconditions.checkNotNull(agentId, "agentId is null");
Preconditions.checkNotNull(location, "location is null");
Preconditions.checkNotNull(slotsDirName, "slotsDirName is null");
Preconditions.checkNotNull(internalUri, "internalUri is null");
Preconditions.checkNotNull(externalUri, "externalUri is null");
Preconditions.checkNotNull(deploymentManagerFactory, "deploymentManagerFactory is null");
Preconditions.checkNotNull(lifecycleManager, "lifecycleManager is null");
Preconditions.checkNotNull(maxLockWait, "maxLockWait is null");
this.agentId = agentId;
this.internalUri = internalUri;
this.externalUri = externalUri;
this.maxLockWait = maxLockWait;
this.location = location;
this.deploymentManagerFactory = deploymentManagerFactory;
this.lifecycleManager = lifecycleManager;
slots = new ConcurrentHashMap<UUID, Slot>();
File slotsDir = new File(slotsDirName);
if (!slotsDir.isDirectory()) {
slotsDir.mkdirs();
Preconditions.checkArgument(slotsDir.isDirectory(), format("Slots directory %s is not a directory", slotsDir));
}
//
// Load existing slots
//
for (DeploymentManager deploymentManager : this.deploymentManagerFactory.loadSlots()) {
UUID slotId = deploymentManager.getSlotId();
URI slotInternalUri = uriBuilderFrom(internalUri).appendPath("/v1/agent/slot/").appendPath(slotId.toString()).build();
URI slotExternalUri = uriBuilderFrom(externalUri).appendPath("/v1/agent/slot/").appendPath(slotId.toString()).build();
Slot slot = new DeploymentSlot(slotInternalUri, slotExternalUri, deploymentManager, lifecycleManager, maxLockWait);
slots.put(slotId, slot);
}
//
// Load resources file
//
Map<String, Integer> resources = ImmutableMap.of();
if (resourcesFilename != null) {
File resourcesFile = new File(resourcesFilename);
if (resourcesFile.canRead()) {
ImmutableMap.Builder<String, Integer> builder = ImmutableMap.builder();
Properties properties = new Properties();
try (InputStream in = new FileInputStream(resourcesFile)) {
properties.load(in);
for (Entry<Object, Object> entry : properties.entrySet()) {
builder.put((String) entry.getKey(), Integer.valueOf((String) entry.getValue()));
}
}
catch (IOException ignored) {
}
resources = builder.build();
}
}
this.resources = resources;
}
public Map<String, Integer> getResources()
{
return resources;
}
public String getAgentId()
{
return agentId;
}
public String getLocation()
{
return location;
}
public AgentStatus getAgentStatus()
{
Builder<SlotStatus> builder = ImmutableList.builder();
for (Slot slot : slots.values()) {
SlotStatus slotStatus = slot.status();
builder.add(slotStatus);
}
AgentStatus agentStatus = new AgentStatus(agentId, ONLINE, null, internalUri, externalUri, location, null, builder.build(), resources);
return agentStatus;
}
public Slot getSlot(UUID slotId)
{
Preconditions.checkNotNull(slotId, "slotId must not be null");
Slot slot = slots.get(slotId);
return slot;
}
public SlotStatus install(Installation installation)
{
// todo name selection is not thread safe
// create slot
DeploymentManager deploymentManager = deploymentManagerFactory.createDeploymentManager(installation);
UUID slotId = deploymentManager.getSlotId();
URI slotInternalUri = uriBuilderFrom(internalUri).appendPath("/v1/agent/slot/").appendPath(slotId.toString()).build();
URI slotExternalUri = uriBuilderFrom(externalUri).appendPath("/v1/agent/slot/").appendPath(slotId.toString()).build();
Slot slot = new DeploymentSlot(slotInternalUri, slotExternalUri, deploymentManager, lifecycleManager, installation, maxLockWait);
slots.put(slotId, slot);
// return last slot status
return slot.getLastSlotStatus();
}
public SlotStatus terminateSlot(UUID slotId)
{
Preconditions.checkNotNull(slotId, "slotId must not be null");
Slot slot = slots.get(slotId);
if (slot == null) {
return null;
}
SlotStatus status = slot.terminate();
if (status.getState() == TERMINATED) {
slots.remove(slotId);
}
return status;
}
public Collection<Slot> getAllSlots()
{
return ImmutableList.copyOf(slots.values());
}
}