All Downloads are FREE. Search and download functionalities are using the official Maven repository.

brooklyn.event.feed.ssh.SshFeed Maven / Gradle / Ivy

package brooklyn.event.feed.ssh;

import static com.google.common.base.Preconditions.checkNotNull;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import brooklyn.entity.basic.EntityLocal;
import brooklyn.event.feed.AbstractFeed;
import brooklyn.event.feed.AttributePollHandler;
import brooklyn.event.feed.DelegatingPollHandler;
import brooklyn.event.feed.Poller;
import brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.collections.MutableMap;

import com.google.common.base.Objects;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;

/**
 * Provides a feed of attribute values, by polling over ssh.
 * 
 * Example usage (e.g. in an entity that extends SoftwareProcessImpl):
 * 
 * {@code
 * private SshFeed feed;
 * 
 * //@Override
 * protected void connectSensors() {
 *   super.connectSensors();
 *   
 *   feed = SshFeed.builder()
 *       .entity(this)
 *       .machine(mySshMachineLachine)
 *       .poll(new SshPollConfig(SERVICE_UP)
 *           .command("rabbitmqctl -q status")
 *           .onSuccess(new Function() {
 *               public Boolean apply(SshPollValue input) {
 *                 return (input.getExitStatus() == 0);
 *               }}))
 *       .build();
 * }
 * 
 * {@literal @}Override
 * protected void disconnectSensors() {
 *   super.disconnectSensors();
 *   if (feed != null) feed.stop();
 * }
 * }
 * 
* * @author aled */ public class SshFeed extends AbstractFeed { public static final Logger log = LoggerFactory.getLogger(SshFeed.class); public static Builder builder() { return new Builder(); } public static class Builder { private EntityLocal entity; private SshMachineLocation machine; private long period = 500; private TimeUnit periodUnits = TimeUnit.MILLISECONDS; private List> polls = Lists.newArrayList(); private volatile boolean built; public Builder entity(EntityLocal val) { this.entity = val; return this; } public Builder machine(SshMachineLocation val) { this.machine = val; return this; } public Builder period(long millis) { return period(millis, TimeUnit.MILLISECONDS); } public Builder period(long val, TimeUnit units) { this.period = val; this.periodUnits = units; return this; } public Builder poll(SshPollConfig config) { polls.add(config); return this; } public SshFeed build() { built = true; SshFeed result = new SshFeed(this); result.start(); return result; } @Override protected void finalize() { if (!built) log.warn("SshFeed.Builder created, but build() never called"); } } private static class SshPollIdentifier { final String command; final Map env; private SshPollIdentifier(String command, Map env) { this.command = checkNotNull(command, "command"); this.env = checkNotNull(env, "env"); } @Override public int hashCode() { return Objects.hashCode(command, env); } @Override public boolean equals(Object other) { if (!(other instanceof SshPollIdentifier)) { return false; } SshPollIdentifier o = (SshPollIdentifier) other; return Objects.equal(command, o.command) && Objects.equal(env, o.env); } } private final SshMachineLocation machine; // Treat as immutable once built private final SetMultimap> polls = HashMultimap.>create(); protected SshFeed(Builder builder) { super(builder.entity); machine = checkNotNull(builder.machine, "machine"); for (SshPollConfig config : builder.polls) { SshPollConfig configCopy = new SshPollConfig(config); if (configCopy.getPeriod() < 0) configCopy.period(builder.period, builder.periodUnits); String command = config.getCommand(); Map env = config.getEnv(); polls.put(new SshPollIdentifier(command, env), configCopy); } } @Override protected void preStart() { for (final SshPollIdentifier pollInfo : polls.keySet()) { Set> configs = polls.get(pollInfo); long minPeriod = Integer.MAX_VALUE; Set> handlers = Sets.newLinkedHashSet(); for (SshPollConfig config : configs) { handlers.add(new AttributePollHandler(config, entity, this)); if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod()); } getPoller().scheduleAtFixedRate( new Callable() { public SshPollValue call() throws Exception { return exec(pollInfo.command, pollInfo.env); }}, new DelegatingPollHandler(handlers), minPeriod); } } @SuppressWarnings("unchecked") private Poller getPoller() { return (Poller) poller; } private SshPollValue exec(String command, Map env) throws IOException { if (log.isTraceEnabled()) log.trace("Ssh polling for {}, executing {} with env {}", new Object[] {machine, command, env}); ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); int exitStatus = machine.run(MutableMap.of("out", stdout, "err", stderr), command, env); return new SshPollValue(machine, exitStatus, new String(stdout.toByteArray()), new String(stderr.toByteArray())); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy