package com.hubspot.singularity.client;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.utils.ZKPaths;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.hubspot.horizon.HttpClient;
import com.hubspot.singularity.SingularityClientCredentials;
@Singleton
public class SingularityClientProvider implements Provider<SingularityClient> {
private static final String DEFAULT_CONTEXT_PATH = "singularity/api";
private final HttpClient httpClient;
private String contextPath = DEFAULT_CONTEXT_PATH;
private List<String> hosts = Collections.emptyList();
private Optional<SingularityClientCredentials> credentials = Optional.absent();
@Inject
public SingularityClientProvider(@Named(SingularityClientModule.HTTP_CLIENT_NAME) HttpClient httpClient) {
this.httpClient = httpClient;
}
@Inject(optional=true) // optional because we have a default
public SingularityClientProvider setContextPath(@Named(SingularityClientModule.CONTEXT_PATH) String contextPath) {
this.contextPath = contextPath;
return this;
}
@Inject(optional=true) // optional in case we use fixed hosts
public SingularityClientProvider setHosts(@Named(SingularityClientModule.HOSTS_PROPERTY_NAME) String commaSeparatedHosts) {
return setHosts(commaSeparatedHosts.split(","));
}
@Inject(optional=true) // optional in case we use Curator
public SingularityClientProvider setCurator(@Named(SingularityClientModule.CURATOR_NAME) CuratorFramework curator) {
return setHosts(getClusterMembers(curator));
}
@Inject(optional=true)
public SingularityClientProvider setHosts(@Named(SingularityClientModule.HOSTS_PROPERTY_NAME) List<String> hosts) {
this.hosts = ImmutableList.copyOf(hosts);
return this;
}
@Inject(optional=true)
public SingularityClientProvider setCredentials(@Named(SingularityClientModule.CREDENTIALS_PROPERTY_NAME) SingularityClientCredentials credentials) {
this.credentials = Optional.of(credentials);
return this;
}
public SingularityClientProvider setHosts(String... hosts) {
this.hosts = Arrays.asList(hosts);
return this;
}
@Override
public SingularityClient get() {
Preconditions.checkState(contextPath != null, "contextPath null");
Preconditions.checkState(!hosts.isEmpty(), "no hosts provided");
return new SingularityClient(contextPath, httpClient, hosts, credentials);
}
public SingularityClient get(Optional<SingularityClientCredentials> credentials) {
Preconditions.checkState(contextPath != null, "contextPath null");
Preconditions.checkState(!hosts.isEmpty(), "no hosts provided");
Preconditions.checkNotNull(credentials);
return new SingularityClient(contextPath, httpClient, hosts, credentials);
}
@Deprecated
public SingularityClient buildClient(String contextPath, String hosts) {
return new SingularityClient(contextPath, httpClient, hosts);
}
static String getClusterMembers(CuratorFramework curator) {
try {
final List<String> leaders = curator.getChildren().forPath(SingularityClusterManager.LEADER_PATH);
final List<String> hosts = Lists.newArrayListWithCapacity(leaders.size());
for (String leader : leaders) {
byte[] data = curator.getData().forPath(ZKPaths.makePath(SingularityClusterManager.LEADER_PATH, leader));
hosts.add(new String(data, UTF_8));
}
return Joiner.on(",").join(hosts);
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
}