/*
* Copyright 2014 SeaClouds
* Contact: SeaClouds
*
* 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 eu.seaclouds.policy;
import java.net.URI;
import java.util.List;
import java.util.Map;
import org.apache.brooklyn.api.entity.Application;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.entity.EntityLocal;
import org.apache.brooklyn.api.sensor.AttributeSensor;
import org.apache.brooklyn.api.sensor.SensorEvent;
import org.apache.brooklyn.api.sensor.SensorEventListener;
import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.config.BasicConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
import org.apache.brooklyn.core.entity.Attributes;
import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
import org.apache.brooklyn.core.policy.AbstractPolicy;
import org.apache.brooklyn.core.sensor.Sensors;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.flags.SetFromFlag;
import org.apache.brooklyn.util.http.HttpTool;
import org.apache.brooklyn.util.http.HttpToolResponse;
import org.apache.brooklyn.util.text.Strings;
import org.apache.http.HttpHeaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import com.google.common.net.MediaType;
import eu.seaclouds.policy.utils.SeaCloudsDcRequestDto;
public class SeaCloudsMonitoringInitializationPolicies extends AbstractPolicy {
private static final Logger LOG = LoggerFactory.getLogger(SeaCloudsMonitoringInitializationPolicies.class);
private static final String RESOURCES = "/resource";
private static final ConfigKey<String> TOSCA_ID = ConfigKeys.newStringConfigKey("tosca.template.id");
@SuppressWarnings("unchecked")
@SetFromFlag("targetEntities")
public static ConfigKey<List<String>> TARGET_ENTITIES = new BasicConfigKey(List.class,
"cloudFoundry.webapp.boundServices",
"List of names of the services that should be bound to this application, " +
"providing credentials for its usage", MutableList.of());
public static ConfigKey<String> SEACLOUDS_DC_ENDPOINT = ConfigKeys
.newStringConfigKey("seacloudsdc.endpoint");
@SuppressWarnings("unchecked")
public static final AttributeSensor<Boolean> MONITORING_CONFIGURED =
Sensors.newBooleanSensor("seaclouds.application.monitoring.configured", "Shows if the" +
"configuration of the seaclouds monitor system was completed");
@Override
public void setEntity(EntityLocal entity) {
super.setEntity(entity);
if (!entity.getApplication().equals(entity)) {
throw new RuntimeException("SeaCloudsMonitoringInitializationPolicies must be attached " +
"to an application");
}
LifecycleListener listener = new LifecycleListener();
entity.subscriptions().subscribe(entity, Attributes.SERVICE_STATE_ACTUAL, listener);
}
private Optional<Entity> findChildEntityByPlanId(Entity app, String planId) {
for (Entity child : app.getChildren()) {
Optional<Entity> subChild = Optional.absent();
if (isCampPlanIdOfEntity(child, planId)
|| isToscaIdPlanOfEntity(child, planId)) {
subChild = Optional.of(child);
}
if ((child.getChildren() != null)
&& (!child.getChildren().isEmpty())
&& (!subChild.isPresent())) {
subChild = findChildEntityByPlanId(child, planId);
}
if (subChild.isPresent()) {
return subChild;
}
}
return Optional.absent();
}
private boolean isCampPlanIdOfEntity(Entity entity, String planId) {
return planId.equalsIgnoreCase(getCampPlanId(entity));
}
private boolean isToscaIdPlanOfEntity(Entity entity, String planId) {
return planId.equalsIgnoreCase(getToscaPlanId(entity));
}
private String getCampPlanId(Entity child) {
return child.getConfig(BrooklynCampConstants.PLAN_ID);
}
private String getToscaPlanId(Entity child) {
return child.getConfig(TOSCA_ID);
}
private class LifecycleListener implements SensorEventListener<Lifecycle> {
private boolean configured;
public LifecycleListener() {
configured = false;
}
@Override
public void onEvent(SensorEvent<Lifecycle> event) {
if (event.getValue().equals(Lifecycle.RUNNING) && !configured) {
configured = true;
configureMontiroringForTargetEntities();
}
}
private void configureMontiroringForTargetEntities() {
for (String targetEntityId : getConfig(TARGET_ENTITIES)) {
Optional<Entity> optionalChild = findChildEntityByPlanId((Application) entity, targetEntityId);
if (optionalChild.isPresent()) {
Entity child = optionalChild.get();
configureSeaCloudDcForAEntity(child, targetEntityId);
}
}
entity.sensors().set(MONITORING_CONFIGURED, true);
}
private void configureSeaCloudDcForAEntity(Entity child, String entityId) {
String mainUri = getMainUri(child);
if (!Strings.isBlank(mainUri)) {
SeaCloudsDcRequestDto requestBody = new SeaCloudsDcRequestDto.Builder()
.type(entityId)
.url(mainUri)
.build();
postSeaCloudsDcConfiguration(requestBody);
}
}
private void postSeaCloudsDcConfiguration(SeaCloudsDcRequestDto requestBody) {
try {
String jsonBody = new ObjectMapper().writeValueAsString(requestBody);
postSeaCloudsDcConfiguration(jsonBody);
} catch (JsonProcessingException e) {
throw new RuntimeException("Something went wrong creating Request body to " +
"configure the SeaCloudsDc for type" + requestBody.getType() + " and " +
"url " + requestBody.getUrl() + ". Message: " + e.getMessage());
}
}
private void postSeaCloudsDcConfiguration(String requestBody) {
URI apiEndpoint = URI.create(getConfig(SEACLOUDS_DC_ENDPOINT) + RESOURCES);
Map<String, String> headers = MutableMap.of(
HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8.toString(),
HttpHeaders.ACCEPT, MediaType.JSON_UTF_8.toString());
HttpToolResponse response = HttpTool
.httpPost(HttpTool.httpClientBuilder().build(), apiEndpoint, headers, requestBody.getBytes());
if (!HttpTool.isStatusCodeHealthy(response.getResponseCode())) {
throw new RuntimeException("Something went wrong during SeaCloudsDc configuration, "
+ response.getResponseCode() + ":" + response.getContentAsString());
}
}
private String getMainUri(Entity child) {
URI mainUri = child.getAttribute(Attributes.MAIN_URI);
if (mainUri != null) {
return mainUri.toString();
}
return Strings.EMPTY;
}
}
}