Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2015-2017 EntIT Software LLC, a Micro Focus company.
*
* 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 com.hpe.caf.autoscale.source.docker.swarm;
import com.hpe.caf.api.HealthResult;
import com.hpe.caf.api.HealthStatus;
import com.hpe.caf.api.autoscale.ScalerException;
import com.hpe.caf.api.autoscale.ScalingConfiguration;
import com.hpe.caf.api.autoscale.ServiceSource;
import com.hpe.caf.autoscale.DockerSwarmAutoscaleConfiguration;
import com.hpe.caf.autoscale.endpoint.HttpClientException;
import com.hpe.caf.autoscale.endpoint.docker.DockerSwarm;
import com.hpe.caf.autoscale.endpoint.docker.DockerSwarmApp;
import com.hpe.caf.autoscale.endpoint.docker.DockerSwarmClient;
import com.hpe.caf.autoscale.endpoint.docker.DockerSwarmFilters;
import static com.hpe.caf.autoscale.endpoint.docker.DockerSwarmFilters.buildServiceFilter;
import com.jayway.jsonpath.DocumentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* A DockerSwarmServiceSource uses HTTP Rest calls to communicate with a Docker Swarm endpoint and retrieve information about running
* tasks. It will create ScalingConfiguration objects based upon this data.
*/
public class DockerSwarmServiceSource implements ServiceSource
{
private final DockerSwarm dockerSwarm;
private final URL url;
private final String stackPath;
private final DockerSwarmAutoscaleConfiguration config;
private static final Logger LOG = LoggerFactory.getLogger(DockerSwarmServiceSource.class);
public DockerSwarmServiceSource(final DockerSwarmAutoscaleConfiguration config, final URL url)
{
this.config = Objects.requireNonNull(config);
this.dockerSwarm = DockerSwarmClient.getInstance(config);
Objects.requireNonNull(dockerSwarm);
this.stackPath = Objects.requireNonNull(config.getStackId());
this.url = Objects.requireNonNull(url);
}
/**
* Call to Docker Swarm and find all running tasks. Create ScalingConfiguration objects based upon the data Docker Swarm returns. If
* the service has the env variable specifying its app name, this will be set as the application owner for that service, but the
* application owner label can override this.
*
* @return available ScalingConfiguration services that have a workload metric
*/
@Override
public Set getServices()
throws ScalerException
{
Set ret = new HashSet<>();
for (DockerSwarmApp app : getDockerSwarmApps()) {
ScalingConfiguration sv = new ScalingConfiguration();
LOG.debug("Checking Docker Swarm service: {}", app.getId());
sv.setId(app.getId());
Map labels = app.getLabels();
if (labels.containsKey(ScalingConfiguration.KEY_WORKLOAD_METRIC)) {
handleStrings(sv, labels);
handleIntegers(sv, labels);
LOG.debug("Returning scaling service: {}", sv);
ret.add(sv);
} else {
LOG.debug("Skipping service {}, workload metric {} not supported", app.getId(), labels.get(
ScalingConfiguration.KEY_WORKLOAD_METRIC));
}
}
return ret;
}
private Collection getDockerSwarmApps()
throws ScalerException
{
try {
Collection apps = new ArrayList<>();
String[] stackPaths;
if (stackPath.contains(",")) {
LOG.info("Multiple Docker Swarm stacks detected: {} splitting on ','.", stackPath);
stackPaths = stackPath.split(",");
} else {
stackPaths = new String[]{stackPath};
}
for (String stackPath : stackPaths) {
apps.addAll(getAllStackApps(stackPath));
}
return apps;
} catch (HttpClientException e) {
throw new ScalerException("Failed to get stack apps", e);
}
}
/**
* Returns all the applications under specified Docker Swarm stack
*/
private Collection getAllStackApps(final String stackId)
{
final Collection apps = new ArrayList<>();
addAllGroupAppsToCollection(apps, stackId);
return apps;
}
/**
* Adds the applications that are under the specified group into the specified collection.
*/
private void addAllGroupAppsToCollection(final Collection apps, final String stackId)
{
assert apps != null;
assert stackId != null;
DocumentContext applicationsResponse = dockerSwarm.getServicesFiltered(buildServiceFilter(
DockerSwarmFilters.ServiceFilterByType.LABEL, DockerSwarmFilters.FilterLabelKeys.DOCKER_STACK, stackId));
// query the list of all the apps, for all apps, that have a label autoscale.metric, in this way we know it is one we should
// be interested in.
LinkedList allAutoscaleAppsInStack = applicationsResponse.read(
"$[?(@.Spec.TaskTemplate.ContainerSpec.Labels['autoscale.metric'])]", LinkedList.class);
if (allAutoscaleAppsInStack.isEmpty()) {
LOG.trace("No valid services in stack which have an autoscale.metric label.: " + stackId);
return;
}
for (LinkedHashMap appObjectInJson : allAutoscaleAppsInStack) {
// Build a dockerswarmapp, by using the ID and labels fields.
DockerSwarmApp app = new DockerSwarmApp();
app.setId(appObjectInJson.get("ID").toString());
// Get the labels object for the object with this ID, we could drill down, or query json again.
LinkedHashMap specNodeMap = (LinkedHashMap) appObjectInJson.get("Spec");
Objects.requireNonNull(specNodeMap, "Application failed to have a valid Spec object with labels.");
LinkedHashMap templateNodeMap = (LinkedHashMap) specNodeMap.get("TaskTemplate");
Objects.requireNonNull(templateNodeMap, "Application failed to have a valid TaskTemplate object with labels.");
LinkedHashMap containerSpecNodeMap = (LinkedHashMap) templateNodeMap.get("ContainerSpec");
Objects.requireNonNull(containerSpecNodeMap, "Application failed to have a valid ContainerSpec object with labels.");
LinkedHashMap labelsNodeMap = (LinkedHashMap) containerSpecNodeMap.get("Labels");
Objects.requireNonNull(labelsNodeMap, "Application failed to have a valid Labels object.");
// LinkedList labels = applicationsResponse.read("$[?(@.ID == '" + app.getId() + "')]");
Map labelsItems = ((Map)labelsNodeMap);
app.setLabels(labelsItems);
apps.add(app);
}
}
private void handleStrings(final ScalingConfiguration sv, final Map labels)
{
sv.setWorkloadMetric(labels.get(ScalingConfiguration.KEY_WORKLOAD_METRIC));
if (labels.containsKey(ScalingConfiguration.KEY_SCALING_TARGET)) {
sv.setScalingTarget(labels.get(ScalingConfiguration.KEY_SCALING_TARGET));
}
if (labels.containsKey(ScalingConfiguration.KEY_SCALING_PROFILE)) {
sv.setScalingProfile(labels.get(ScalingConfiguration.KEY_SCALING_PROFILE));
}
}
private void handleIntegers(final ScalingConfiguration sv, final Map labels)
{
if (labels.containsKey(ScalingConfiguration.KEY_INTERVAL)) {
sv.setInterval(Integer.parseInt(labels.get(ScalingConfiguration.KEY_INTERVAL)));
}
if (labels.containsKey(ScalingConfiguration.KEY_MAX_INSTANCES)) {
sv.setMaxInstances(Integer.parseInt(labels.get(ScalingConfiguration.KEY_MAX_INSTANCES)));
}
if (labels.containsKey(ScalingConfiguration.KEY_MIN_INSTANCES)) {
sv.setMinInstances(Integer.parseInt(labels.get(ScalingConfiguration.KEY_MIN_INSTANCES)));
}
if (labels.containsKey(ScalingConfiguration.KEY_BACKOFF_AMOUNT)) {
sv.setBackoffAmount(Integer.parseInt(labels.get(ScalingConfiguration.KEY_BACKOFF_AMOUNT)));
}
}
/**
* Try a trivial connection to the HTTP endpoint.
*
* @return whether a connection to the docker swarm works or not
*/
@Override
public HealthResult healthCheck()
{
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(url.getHost(), url.getPort()), Integer.valueOf(config.getHealthCheckTimeoutInSecs().toString())*1000);
return HealthResult.RESULT_HEALTHY;
} catch (IOException e) {
LOG.warn("Connection failure to HTTP endpoint", e);
return new HealthResult(HealthStatus.UNHEALTHY, "Cannot connect to REST endpoint: " + url);
}
}
}