/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.brooklyn.feed.ssh;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.apache.brooklyn.api.sensor.AttributeSensor;
import org.apache.brooklyn.core.feed.PollConfig;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
public class SshPollConfig<T> extends PollConfig<SshPollValue, T, SshPollConfig<T>> {
private Supplier<String> commandSupplier;
private List<Supplier<Map<String,String>>> dynamicEnvironmentSupplier = MutableList.of();
public static final Predicate<SshPollValue> DEFAULT_SUCCESS = new Predicate<SshPollValue>() {
@Override
public boolean apply(@Nullable SshPollValue input) {
return input != null && input.getExitStatus() == 0;
}};
public SshPollConfig(AttributeSensor<T> sensor) {
super(sensor);
super.checkSuccess(DEFAULT_SUCCESS);
}
public SshPollConfig(SshPollConfig<T> other) {
super(other);
commandSupplier = other.commandSupplier;
}
/** @deprecated since 0.7.0; use {@link #getCommandSupplier()} and resolve just-in-time */
public String getCommand() {
return getCommandSupplier().get();
}
public Supplier<String> getCommandSupplier() {
return commandSupplier;
}
/** @deprecated since 0.7.0; use {@link #getEnvSupplier()} and resolve just-in-time */
public Map<String, String> getEnv() {
return getEnvSupplier().get();
}
@SuppressWarnings("unused")
public Supplier<Map<String,String>> getEnvSupplier() {
if (true) return new CombiningEnvSupplier(dynamicEnvironmentSupplier);
// TODO Kept in case it's persisted; new code will not use this.
return new Supplier<Map<String,String>>() {
@Override
public Map<String, String> get() {
Map<String,String> result = MutableMap.of();
for (Supplier<Map<String, String>> envS: dynamicEnvironmentSupplier) {
if (envS!=null) {
Map<String, String> envM = envS.get();
if (envM!=null) {
mergeEnvMaps(envM, result);
}
}
}
return result;
}
private void mergeEnvMaps(Map<String,String> supplied, Map<String,String> target) {
if (supplied==null) return;
// as the value is a string there is no need to look at deep merge behaviour
target.putAll(supplied);
}
};
}
private static class CombiningEnvSupplier implements Supplier<Map<String,String>> {
private final List<Supplier<Map<String, String>>> dynamicEnvironmentSupplier;
public CombiningEnvSupplier(List<Supplier<Map<String,String>>> dynamicEnvironmentSupplier) {
this.dynamicEnvironmentSupplier = checkNotNull(dynamicEnvironmentSupplier, "dynamicEnvironmentSupplier");
}
@Override
public Map<String, String> get() {
Map<String,String> result = MutableMap.of();
for (Supplier<Map<String, String>> envS: dynamicEnvironmentSupplier) {
if (envS!=null) {
Map<String, String> envM = envS.get();
if (envM!=null) {
mergeEnvMaps(envM, result);
}
}
}
return result;
}
protected void mergeEnvMaps(Map<String,String> supplied, Map<String,String> target) {
if (supplied==null) return;
// as the value is a string there is no need to look at deep merge behaviour
target.putAll(supplied);
}
@Override
public int hashCode() {
return dynamicEnvironmentSupplier.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof CombiningEnvSupplier)) return false;
CombiningEnvSupplier o = (CombiningEnvSupplier) obj;
return Objects.equal(dynamicEnvironmentSupplier, o.dynamicEnvironmentSupplier);
}
@Override
public String toString() {
return "CombiningEnvSupplier("+dynamicEnvironmentSupplier+")";
}
}
public SshPollConfig<T> command(String val) { return command(Suppliers.ofInstance(val)); }
public SshPollConfig<T> command(Supplier<String> val) {
this.commandSupplier = val;
return this;
}
/** add the given env param; sequence is as per {@link #env(Supplier)} */
public SshPollConfig<T> env(String key, String val) {
return env(Collections.singletonMap(key, val));
}
/** add the given env params; sequence is as per {@link #env(Supplier)}.
* behaviour is undefined if the map supplied here is subsequently changed.
* <p>
* if a map's contents might change, use {@link #env(Supplier)} */
public SshPollConfig<T> env(Map<String,String> val) {
if (val==null) return this;
return env(Suppliers.ofInstance(val));
}
/**
* adds the given dynamic supplier of environment variables.
* <p>
* use of a supplier allows env vars to be computed on each execution,
* for example to take the most recent sensor values.
* <p>
* in the case of multiple map suppliers, static maps, or static {@link #env(String, String)}
* key value pairs, the order in which they are specified here is the order
* in which they are computed and applied.
**/
public SshPollConfig<T> env(Supplier<Map<String,String>> val) {
Preconditions.checkNotNull(val);
dynamicEnvironmentSupplier.add(val);
return this;
}
@Override protected String toStringBaseName() { return "ssh"; }
@Override protected Object toStringPollSource() {
if (getCommandSupplier()==null) return null;
String command = getCommandSupplier().get();
return command;
}
@Override protected MutableList<Object> equalsFields() {
return super.equalsFields()
.appendIfNotNull(getCommandSupplier()!=null ? getCommandSupplier().get() : null)
.appendIfNotNull(getEnvSupplier()!=null ? getEnvSupplier().get() : null);
}
}