package io.cattle.platform.agent.connection.simulator.impl;
import static io.cattle.platform.core.constants.InstanceConstants.*;
import io.cattle.platform.agent.connection.simulator.AgentConnectionSimulator;
import io.cattle.platform.agent.connection.simulator.AgentSimulatorEventProcessor;
import io.cattle.platform.configitem.events.ConfigUpdate;
import io.cattle.platform.configitem.model.Client;
import io.cattle.platform.configitem.model.ItemVersion;
import io.cattle.platform.configitem.request.ConfigUpdateItem;
import io.cattle.platform.configitem.version.dao.ConfigItemStatusDao;
import io.cattle.platform.core.constants.AgentConstants;
import io.cattle.platform.core.model.Agent;
import io.cattle.platform.deferred.util.DeferredUtils;
import io.cattle.platform.eventing.model.Event;
import io.cattle.platform.eventing.model.EventVO;
import io.cattle.platform.json.JsonMapper;
import io.cattle.platform.object.ObjectManager;
import io.cattle.platform.server.context.ServerContext;
import io.cattle.platform.server.context.ServerContext.BaseProtocol;
import io.cattle.platform.util.type.CollectionUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
public class SimulatorStartStopProcessor implements AgentSimulatorEventProcessor {
private static final Pattern SHUTDOWN = Pattern.compile(".*simShutdownAfter\",\"([0-9]+)");
private static final Pattern FORGET = Pattern.compile(".*simForgetImmediately.*");
private static final Pattern DISCONNECT = Pattern.compile(".*simDisconnectAgent.*");
private static final String SIM_CREATE_ANOTHER = "simCreateAnother_";
private static final Pattern CREATE_ANOTHER = Pattern.compile(".*simCreateAnother_.*");
@Inject
ConfigItemStatusDao configItemStatusDao;
@Inject
SimulatorConfigUpdateProcessor configUpdateProcessor;
@Inject
ObjectManager objectManager;
JsonMapper jsonMapper;
ScheduledExecutorService scheduleExecutorService;
@SuppressWarnings("unchecked")
@Override
public Event handle(final AgentConnectionSimulator simulator, Event event) throws Exception {
String action = null;
if ("compute.instance.activate".equals(event.getName())) {
action = "add";
} else if ("compute.instance.deactivate".equals(event.getName())) {
action = "stop";
} else if ("compute.instance.remove".equals(event.getName())) {
action = "remove";
}
if (action == null) {
return null;
}
String eventString = jsonMapper.writeValueAsString(event);
Map<String, Object> instance = (Map<String, Object>)CollectionUtils.getNestedValue(event.getData(), "instanceHostMap", "instance");
Map<String, Object> update = null;
String externalId = (String)instance.get("externalId");
if (externalId == null) {
externalId = io.cattle.platform.util.resource.UUID.randomUUID().toString();
update = CollectionUtils.asMap("instanceHostMap", CollectionUtils.asMap("instance", CollectionUtils.asMap("externalId", externalId)));
}
final Object uuid = instance.get("uuid");
Object image = CollectionUtils.getNestedValue(instance, "data", "fields", "imageUuid");
String imageUuid = image != null ? image.toString() : "sim:foo";
if (uuid != null) {
boolean found = simulator.getInstances().containsKey(uuid.toString());
boolean forget = FORGET.matcher(eventString).matches();
if (forget) {
simulator.getInstances().remove(uuid.toString());
} else if ("add".equals(action)) {
simulator.getInstances().put(uuid.toString(), new Object[] { STATE_RUNNING, externalId, imageUuid, new Date().getTime() });
} else if ("stop".equals(action) && found) {
simulator.getInstances().put(uuid.toString(), new Object[] { STATE_STOPPED, externalId, imageUuid, new Date().getTime() });
} else {
simulator.getInstances().remove(uuid.toString());
}
}
Matcher m = SHUTDOWN.matcher(eventString);
if (m.matches()) {
scheduleExecutorService.schedule(new Runnable() {
@Override
public void run() {
simulator.getInstances().remove(uuid.toString());
}
}, Long.parseLong(m.group(1)), TimeUnit.SECONDS);
}
if (DISCONNECT.matcher(eventString).matches()) {
simulator.setOpen(false);
}
if (CREATE_ANOTHER.matcher(eventString).matches()) {
String name = (String)instance.get("name");
String anotherExternalId = StringUtils.substringAfter(name, SIM_CREATE_ANOTHER);
simulator.getInstances().put("name-" + anotherExternalId, new Object[] { STATE_RUNNING, anotherExternalId, imageUuid,
new Date().getTime() });
}
Number agentId = (Number)instance.get("agentId");
if (agentId != null && "add".equals(action)) {
publishItemUpdates(agentId.longValue());
}
return EventVO.reply(event).withData(update);
}
protected void publishItemUpdates(long agentId) {
Client client = new Client(Agent.class, agentId);
Map<String, ItemVersion> version = configItemStatusDao.getApplied(client);
List<ConfigUpdateItem> items = new ArrayList<>(version.size());
for (String name : version.keySet()) {
items.add(new ConfigUpdateItem(name));
}
final Agent agent = objectManager.loadResource(Agent.class, agentId);
final Event configUpdate = new ConfigUpdate(client.getEventName(), ServerContext.getHostApiBaseUrl(BaseProtocol.HTTP), items)
.withResourceType(AgentConstants.TYPE).withResourceId(Long.toString(agentId));
DeferredUtils.defer(new Runnable() {
@Override
public void run() {
try {
configUpdateProcessor.handle(agent, configUpdate);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
});
}
public JsonMapper getJsonMapper() {
return jsonMapper;
}
@Inject
public void setJsonMapper(JsonMapper jsonMapper) {
this.jsonMapper = jsonMapper;
}
public ScheduledExecutorService getScheduleExecutorService() {
return scheduleExecutorService;
}
@Inject
public void setScheduleExecutorService(ScheduledExecutorService scheduleExecutorService) {
this.scheduleExecutorService = scheduleExecutorService;
}
}