/*
* 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.ambari.server.controller.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.StaticallyInject;
import org.apache.ambari.server.agent.ActionQueue;
import org.apache.ambari.server.agent.AlertExecutionCommand;
import org.apache.ambari.server.api.resources.AlertDefResourceDefinition;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
import org.apache.ambari.server.controller.spi.NoSuchResourceException;
import org.apache.ambari.server.controller.spi.Predicate;
import org.apache.ambari.server.controller.spi.Request;
import org.apache.ambari.server.controller.spi.RequestStatus;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
import org.apache.ambari.server.controller.spi.SystemException;
import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
import org.apache.ambari.server.controller.utilities.PropertyHelper;
import org.apache.ambari.server.events.AlertDefinitionDisabledEvent;
import org.apache.ambari.server.events.AlertHashInvalidationEvent;
import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
import org.apache.ambari.server.security.authorization.AuthorizationException;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.alert.AlertDefinition;
import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
import org.apache.ambari.server.state.alert.AlertDefinitionHash;
import org.apache.ambari.server.state.alert.Scope;
import org.apache.ambari.server.state.alert.SourceType;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.inject.Inject;
/**
* ResourceProvider for Alert Definitions
*/
@StaticallyInject
public class AlertDefinitionResourceProvider extends AbstractControllerResourceProvider {
protected static final String ALERT_DEF = "AlertDefinition";
protected static final String ALERT_DEF_CLUSTER_NAME = "AlertDefinition/cluster_name";
protected static final String ALERT_DEF_ID = "AlertDefinition/id";
protected static final String ALERT_DEF_NAME = "AlertDefinition/name";
protected static final String ALERT_DEF_LABEL = "AlertDefinition/label";
protected static final String ALERT_DEF_HELP_URL = "AlertDefinition/help_url";
protected static final String ALERT_DEF_DESCRIPTION = "AlertDefinition/description";
protected static final String ALERT_DEF_INTERVAL = "AlertDefinition/interval";
protected static final String ALERT_DEF_SERVICE_NAME = "AlertDefinition/service_name";
protected static final String ALERT_DEF_COMPONENT_NAME = "AlertDefinition/component_name";
protected static final String ALERT_DEF_ENABLED = "AlertDefinition/enabled";
protected static final String ALERT_DEF_SCOPE = "AlertDefinition/scope";
protected static final String ALERT_DEF_IGNORE_HOST = "AlertDefinition/ignore_host";
protected static final String ALERT_DEF_REPEAT_TOLERANCE = "AlertDefinition/repeat_tolerance";
protected static final String ALERT_DEF_REPEAT_TOLERANCE_ENABLED = "AlertDefinition/repeat_tolerance_enabled";
protected static final String ALERT_DEF_SOURCE = "AlertDefinition/source";
protected static final String ALERT_DEF_SOURCE_TYPE = "AlertDefinition/source/type";
private static Set<String> pkPropertyIds = new HashSet<>(
Arrays.asList(ALERT_DEF_ID, ALERT_DEF_NAME));
private static Gson gson = new Gson();
@Inject
private static AlertDefinitionHash alertDefinitionHash;
@Inject
private static AlertDefinitionDAO alertDefinitionDAO = null;
/**
* Used for coercing an {@link AlertDefinitionEntity} to an
* {@link AlertDefinition}.
*/
@Inject
private static AlertDefinitionFactory definitionFactory;
/**
* Used to enqueue commands to send to the agents when running an alert
* on-demand.
*/
@Inject
private static ActionQueue actionQueue;
/**
* Publishes the following events:
* <ul>
* <li>{@link AlertDefinitionDisabledEvent} when an alert definition is
* disabled</li>
* </ul>
*/
@Inject
private static AmbariEventPublisher eventPublisher;
/**
* The property ids for an alert defintion resource.
*/
private static final Set<String> PROPERTY_IDS = new HashSet<>();
/**
* The key property ids for an alert definition resource.
*/
private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new HashMap<>();
static {
// properties
PROPERTY_IDS.add(ALERT_DEF_CLUSTER_NAME);
PROPERTY_IDS.add(ALERT_DEF_SERVICE_NAME);
PROPERTY_IDS.add(ALERT_DEF_COMPONENT_NAME);
PROPERTY_IDS.add(ALERT_DEF_ID);
PROPERTY_IDS.add(ALERT_DEF_NAME);
PROPERTY_IDS.add(ALERT_DEF_LABEL);
PROPERTY_IDS.add(ALERT_DEF_DESCRIPTION);
PROPERTY_IDS.add(ALERT_DEF_HELP_URL);
PROPERTY_IDS.add(ALERT_DEF_INTERVAL);
PROPERTY_IDS.add(ALERT_DEF_ENABLED);
PROPERTY_IDS.add(ALERT_DEF_SCOPE);
PROPERTY_IDS.add(ALERT_DEF_IGNORE_HOST);
PROPERTY_IDS.add(ALERT_DEF_REPEAT_TOLERANCE);
PROPERTY_IDS.add(ALERT_DEF_REPEAT_TOLERANCE_ENABLED);
PROPERTY_IDS.add(ALERT_DEF_SOURCE);
// keys
KEY_PROPERTY_IDS.put(Resource.Type.AlertDefinition, ALERT_DEF_ID);
KEY_PROPERTY_IDS.put(Resource.Type.Cluster, ALERT_DEF_CLUSTER_NAME);
}
/**
* Constructor.
*
* @param controller
*/
AlertDefinitionResourceProvider(AmbariManagementController controller) {
super(PROPERTY_IDS, KEY_PROPERTY_IDS, controller);
}
@Override
protected Set<String> getPKPropertyIds() {
return pkPropertyIds;
}
@Override
public RequestStatus createResources(final Request request) throws SystemException,
UnsupportedPropertyException, ResourceAlreadyExistsException,
NoSuchParentResourceException {
createResources(new Command<Void>() {
@Override
public Void invoke() throws AmbariException, AuthorizationException {
createAlertDefinitions(request.getProperties());
return null;
}
});
notifyCreate(Resource.Type.AlertDefinition, request);
return getRequestStatus(null);
}
private void createAlertDefinitions(Set<Map<String, Object>> requestMaps)
throws AmbariException, AuthorizationException {
List<AlertDefinitionEntity> entities = new ArrayList<>();
String clusterName = null;
for (Map<String, Object> requestMap : requestMaps) {
AlertDefinitionEntity entity = new AlertDefinitionEntity();
populateEntity(entity, requestMap);
entities.add(entity);
if (null == clusterName) {
clusterName = (String) requestMap.get(ALERT_DEF_CLUSTER_NAME);
}
}
for (AlertDefinitionEntity entity : entities) {
alertDefinitionDAO.create(entity);
long clusterId = entity.getClusterId();
// invalidate the hash and publish the event
final Set<String> invalidatedHosts = alertDefinitionHash.invalidateHosts(entity);
AlertHashInvalidationEvent event = new AlertHashInvalidationEvent(
clusterId, invalidatedHosts);
eventPublisher.publish(event);
}
}
/**
* {@inheritDoc}
*/
@Override
public Set<Resource> getResources(Request request, Predicate predicate)
throws SystemException, UnsupportedPropertyException,
NoSuchResourceException, NoSuchParentResourceException {
Set<String> requestPropertyIds = getRequestPropertyIds(request, predicate);
// use a collection which preserves order since JPA sorts the results
Set<Resource> results = new LinkedHashSet<>();
for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
String clusterName = (String) propertyMap.get(ALERT_DEF_CLUSTER_NAME);
if (null == clusterName || clusterName.isEmpty()) {
throw new IllegalArgumentException("Invalid argument, cluster name is required");
}
String id = (String) propertyMap.get(ALERT_DEF_ID);
if (null != id) {
AlertDefinitionEntity entity = alertDefinitionDAO.findById(Long.parseLong(id));
if (null != entity) {
AlertResourceProviderUtils.verifyViewAuthorization(entity);
results.add(toResource(clusterName, entity, requestPropertyIds));
}
} else {
Cluster cluster = null;
try {
cluster = getManagementController().getClusters().getCluster(clusterName);
} catch (AmbariException e) {
throw new NoSuchResourceException("Parent Cluster resource doesn't exist", e);
}
List<AlertDefinitionEntity> entities = alertDefinitionDAO.findAll(cluster.getClusterId());
// Any service name that is not empty or equal to "AMBARI" indicates a service-level alert
boolean serviceLevelAuthorization = AlertResourceProviderUtils.hasViewAuthorization("_SERVICE_NAME_", cluster.getResourceId());
boolean clusterLevelAuthorization = AlertResourceProviderUtils.hasViewAuthorization("", cluster.getResourceId());
for (AlertDefinitionEntity entity : entities) {
String serviceName = entity.getServiceName();
// Include the alert in the results if the authenticated user is authorized to get it
if((StringUtils.isEmpty(serviceName) || "AMBARI".equals(serviceName))
? clusterLevelAuthorization
: serviceLevelAuthorization) {
results.add(toResource(clusterName, entity, requestPropertyIds));
}
}
}
}
return results;
}
/**
* {@inheritDoc}
*/
@Override
public RequestStatus updateResources(Request request, Predicate predicate)
throws SystemException, UnsupportedPropertyException,
NoSuchResourceException, NoSuchParentResourceException {
// check the update directives to see if there is a request to run
// the alert definition immediately
Map<String, String> requestInfoProps = request.getRequestInfoProperties();
if (null != requestInfoProps
&& requestInfoProps.containsKey(AlertDefResourceDefinition.EXECUTE_IMMEDIATE_DIRECTIVE)) {
Set<Map<String,Object>> predicateMaps = getPropertyMaps(predicate);
for (Map<String, Object> propertyMap : predicateMaps) {
scheduleImmediateAlert(propertyMap);
}
return getRequestStatus(null);
}
// if an AlertDefinition property body was specified, perform the update
for (Map<String, Object> requestPropMap : request.getProperties()) {
for (Map<String, Object> propertyMap : getPropertyMaps(requestPropMap, predicate)) {
String stringId = (String) propertyMap.get(ALERT_DEF_ID);
long id = Long.parseLong(stringId);
AlertDefinitionEntity entity = alertDefinitionDAO.findById(id);
if (null == entity) {
continue;
}
// capture the state of the old entity
boolean oldEnabled = entity.getEnabled();
try {
populateEntity(entity, propertyMap);
alertDefinitionDAO.merge(entity);
// invalidate and publish the definition hash
Set<String> invalidatedHosts = alertDefinitionHash.invalidateHosts(entity);
AlertHashInvalidationEvent event = new AlertHashInvalidationEvent(
entity.getClusterId(), invalidatedHosts);
eventPublisher.publish(event);
} catch (AmbariException ae) {
LOG.error("Unable to find cluster when updating alert definition", ae);
}
// if the old state was enabled and the new state is not, trigger
// a disabled event
if (oldEnabled && !entity.getEnabled()) {
AlertDefinitionDisabledEvent event = new AlertDefinitionDisabledEvent(
entity.getClusterId(), entity.getDefinitionId());
eventPublisher.publish(event);
}
}
}
notifyUpdate(Resource.Type.AlertDefinition, request, predicate);
return getRequestStatus(null);
}
/**
* {@inheritDoc}
*/
@Override
public RequestStatus deleteResources(Request request, Predicate predicate)
throws SystemException, UnsupportedPropertyException,
NoSuchResourceException, NoSuchParentResourceException {
Set<Resource> resources = getResources(
new RequestImpl(null, null, null, null), predicate);
Set<Long> definitionIds = new HashSet<>();
for (final Resource resource : resources) {
Long id = (Long) resource.getPropertyValue(ALERT_DEF_ID);
definitionIds.add(id);
}
for (Long definitionId : definitionIds) {
LOG.info("Deleting alert definition {}", definitionId);
final AlertDefinitionEntity entity = alertDefinitionDAO.findById(definitionId.longValue());
AlertResourceProviderUtils.verifyManageAuthorization(entity);
modifyResources(new Command<Void>() {
@Override
public Void invoke() throws AmbariException {
long clusterId = entity.getClusterId();
// remove the entity
alertDefinitionDAO.remove(entity);
// publish the hash invalidation
final Set<String> invalidatedHosts = alertDefinitionHash.invalidateHosts(entity);
AlertHashInvalidationEvent event = new AlertHashInvalidationEvent(
clusterId, invalidatedHosts);
eventPublisher.publish(event);
return null;
}
});
}
notifyDelete(Resource.Type.AlertDefinition, predicate);
return getRequestStatus(null);
}
/**
* Merges the map of properties into the specified entity. If the entity is
* being created, an {@link IllegalArgumentException} is thrown when a
* required property is absent. When updating, missing properties are assume
* to not have changed.
*
* @param entity
* the entity to merge the properties into (not {@code null}).
* @param requestMap
* the map of properties (not {@code null}).
* @throws AmbariException
*/
private void populateEntity(AlertDefinitionEntity entity,
Map<String, Object> requestMap) throws AmbariException, AuthorizationException {
// some fields are required on creation; on update we keep what's there
boolean bCreate = true;
if (null != entity.getDefinitionId()) {
bCreate = false;
}
String clusterName = (String) requestMap.get(ALERT_DEF_CLUSTER_NAME);
String definitionName = (String) requestMap.get(ALERT_DEF_NAME);
String serviceName = (String) requestMap.get(ALERT_DEF_SERVICE_NAME);
String componentName = (String) requestMap.get(ALERT_DEF_COMPONENT_NAME);
String type = (String) requestMap.get(ALERT_DEF_SOURCE_TYPE);
String label = (String) requestMap.get(ALERT_DEF_LABEL);
String helpURL = (String) requestMap.get(ALERT_DEF_HELP_URL);
String description = (String) requestMap.get(ALERT_DEF_DESCRIPTION);
String desiredScope = (String) requestMap.get(ALERT_DEF_SCOPE);
Integer interval = null;
if (requestMap.containsKey(ALERT_DEF_INTERVAL)) {
interval = Integer.valueOf((String) requestMap.get(ALERT_DEF_INTERVAL));
}
Boolean enabled = null;
if (requestMap.containsKey(ALERT_DEF_ENABLED)) {
enabled = Boolean.parseBoolean((String) requestMap.get(ALERT_DEF_ENABLED));
} else if (bCreate) {
enabled = Boolean.TRUE;
}
Boolean ignoreHost = null;
if (requestMap.containsKey(ALERT_DEF_IGNORE_HOST)) {
ignoreHost = Boolean.parseBoolean((String) requestMap.get(ALERT_DEF_IGNORE_HOST));
} else if (bCreate) {
ignoreHost = Boolean.FALSE;
}
Scope scope = null;
if (null != desiredScope && desiredScope.length() > 0) {
scope = Scope.valueOf(desiredScope);
}
SourceType sourceType = null;
if (null != type && type.length() > 0) {
sourceType = SourceType.valueOf(type);
}
// if not specified when creating an alert definition, the scope is
// assumed to be ANY
if (null == scope && bCreate) {
scope = Scope.ANY;
}
Integer repeatTolerance = null;
if (requestMap.containsKey(ALERT_DEF_REPEAT_TOLERANCE)) {
repeatTolerance = Integer.valueOf((String) requestMap.get(ALERT_DEF_REPEAT_TOLERANCE));
}
Boolean repeatToleranceEnabled = null;
if (requestMap.containsKey(ALERT_DEF_REPEAT_TOLERANCE_ENABLED)) {
repeatToleranceEnabled = Boolean.valueOf(
requestMap.get(ALERT_DEF_REPEAT_TOLERANCE_ENABLED).toString());
}
if (StringUtils.isEmpty(clusterName)) {
throw new IllegalArgumentException(
"Invalid argument, cluster name is required");
}
if (bCreate && !requestMap.containsKey(ALERT_DEF_INTERVAL)) {
throw new IllegalArgumentException("Check interval must be specified");
}
if (bCreate && StringUtils.isEmpty(definitionName)) {
throw new IllegalArgumentException("Definition name must be specified");
}
if (bCreate && StringUtils.isEmpty(serviceName)) {
throw new IllegalArgumentException("Service name must be specified");
}
// on creation, source type is required
if (bCreate && null == sourceType) {
throw new IllegalArgumentException(String.format(
"Source type must be specified and one of %s",
EnumSet.allOf(SourceType.class)));
}
// !!! The AlertDefinition "source" field is a nested JSON object;
// build a JSON representation from the flat properties and then
// serialize that JSON object as a string
Map<String,JsonObject> jsonObjectMapping = new HashMap<>();
// for every property in the request, if it's a source property, then
// add it to the JSON model
for (Entry<String, Object> entry : requestMap.entrySet()) {
String propertyKey = entry.getKey();
// only handle "source" subproperties
if (!propertyKey.startsWith(ALERT_DEF_SOURCE)) {
continue;
}
// gets a JSON object to add the property to; this will create the
// property and all of its parent properties recursively if necessary
JsonObject jsonObject = getJsonObjectMapping(ALERT_DEF_SOURCE,
jsonObjectMapping, propertyKey);
String propertyName = PropertyHelper.getPropertyName(propertyKey);
Object entryValue = entry.getValue();
// determine if the object is a collection, a number, or a string
if( entryValue instanceof Collection<?> ){
// add it as a tree (collection)
JsonElement jsonElement = gson.toJsonTree(entryValue);
jsonObject.add(propertyName, jsonElement);
} else if (entryValue instanceof Number) {
// add it as a number
jsonObject.addProperty(propertyName, (Number) entryValue);
} else {
// it's a string, but it could still be a Number since Ambari's higher
// level JSON processor converts all JSON bodies into Map<String,String>
// instead of Map<String,Object>
String value = entryValue.toString();
if (StringUtils.isNotEmpty(value) && NumberUtils.isNumber(value)) {
Number number = NumberUtils.createNumber(value);
jsonObject.addProperty(propertyName, number);
} else {
jsonObject.addProperty(propertyName, value);
}
}
}
// "source" must be filled in when creating
JsonObject source = jsonObjectMapping.get(ALERT_DEF_SOURCE);
if (bCreate && (null == source || 0 == source.entrySet().size())) {
throw new IllegalArgumentException("Source must be specified");
}
Clusters clusters = getManagementController().getClusters();
Cluster cluster = clusters.getCluster(clusterName);
Long clusterId = cluster.getClusterId();
boolean managed = false;
boolean toggled = false;
// at this point, we have either validated all required properties or
// we are using the exiting entity properties where not defined, so we
// can do simply null checks
if (!clusterId.equals(entity.getClusterId())) {
entity.setClusterId(clusterId);
managed = true;
}
if ((null != componentName) && !componentName.equals(entity.getComponentName())) {
entity.setComponentName(componentName);
managed = true;
}
if ((null != definitionName) && !definitionName.equals(entity.getDefinitionName())) {
entity.setDefinitionName(definitionName);
managed = true;
}
if ((null != label) && !label.equals(entity.getLabel())) {
entity.setLabel(label);
managed = true;
}
if ((null != helpURL) && !helpURL.equals(entity.getHelpURL())) {
entity.setHelpURL(helpURL);
managed = true;
}
if ((null != description) && !description.equals(entity.getDescription())) {
entity.setDescription(description);
managed = true;
}
if ((null != enabled) && !enabled.equals(entity.getEnabled())) {
entity.setEnabled(enabled);
toggled = true;
}
if ((null != ignoreHost) && !ignoreHost.equals(entity.isHostIgnored())) {
entity.setHostIgnored(ignoreHost);
managed = true;
}
if ((null != interval) && !interval.equals(entity.getScheduleInterval())) {
entity.setScheduleInterval(interval);
managed = true;
}
if ((null != serviceName) && !serviceName.equals(entity.getServiceName())) {
entity.setServiceName(serviceName);
managed = true;
}
if ((null != sourceType) && !sourceType.equals(entity.getSourceType())) {
entity.setSourceType(sourceType);
managed = true;
}
if (null != source) {
entity.setSource(source.toString());
managed = true;
}
if ((null != scope) && !scope.equals(entity.getScope())) {
entity.setScope(scope);
managed = true;
}
// repeat tolerance is only for non-AGGREGATE alerts
if (entity.getSourceType() != SourceType.AGGREGATE) {
if (null != repeatTolerance) {
entity.setRepeatTolerance(repeatTolerance);
managed = true;
}
if (null != repeatToleranceEnabled) {
entity.setRepeatToleranceEnabled(repeatToleranceEnabled);
managed = true;
}
}
if (managed) {
AlertResourceProviderUtils.verifyManageAuthorization(entity);
} else if (toggled) {
AlertResourceProviderUtils.verifyToggleAuthorization(entity);
}
entity.setHash(UUID.randomUUID().toString());
}
/**
* Gets a {@link JsonObject} that the specified flattened property should be
* set on, creating all parent {@link JsonObject} instances as needed. This
* will turn {code AlertDefinition/source/reporting/critical/text} into
*
* <pre>
* AlertDefinition/source: {
* reporting: {
* critical: {
* text
* }
* }
* }
* </pre>
*
* Where the the following {@link JsonObject} instances are created:
*
* <pre>
* AlertDefinition/source
* Reporting
* Critical
* property 'text',
* property 'value',
* etc
* </pre>
*
* @param root
* the flattened property which will be considered the root.
* @param jsonObjectMapping
* a mapping of flattened property to {@link JsonObject}.
* @param propertyKey
* the key to get the {@link JsonObject} for.
* @return the {@link JsonObject} that cooresponds to the specified key.
*/
private JsonObject getJsonObjectMapping(String root,
Map<String, JsonObject> jsonObjectMapping, String propertyKey) {
// if there is already a mapping for the key, return the mapping
if (jsonObjectMapping.containsKey(propertyKey)) {
return jsonObjectMapping.get(propertyKey);
}
if (root.equals(propertyKey)) {
JsonObject jsonRoot = jsonObjectMapping.get(root);
if (null == jsonRoot) {
jsonRoot = new JsonObject();
jsonObjectMapping.put(root, jsonRoot);
}
return jsonRoot;
}
String propertyCategory = PropertyHelper.getPropertyCategory(propertyKey);
JsonObject categoryJson = jsonObjectMapping.get(propertyCategory);
if (null == categoryJson) {
JsonObject parent = getJsonObjectMapping(root, jsonObjectMapping,
propertyCategory);
categoryJson = new JsonObject();
jsonObjectMapping.put(propertyCategory, categoryJson);
String categoryName = PropertyHelper.getPropertyName(propertyCategory);
parent.add(categoryName, categoryJson);
}
return categoryJson;
}
private Resource toResource(String clusterName,
AlertDefinitionEntity entity, Set<String> requestedIds) {
Resource resource = new ResourceImpl(Resource.Type.AlertDefinition);
resource.setProperty(ALERT_DEF_ID, entity.getDefinitionId());
resource.setProperty(ALERT_DEF_CLUSTER_NAME, clusterName);
resource.setProperty(ALERT_DEF_NAME, entity.getDefinitionName());
resource.setProperty(ALERT_DEF_LABEL, entity.getLabel());
setResourceProperty(resource, ALERT_DEF_DESCRIPTION, entity.getDescription(), requestedIds);
setResourceProperty(resource, ALERT_DEF_INTERVAL, entity.getScheduleInterval(), requestedIds);
setResourceProperty(resource, ALERT_DEF_SERVICE_NAME, entity.getServiceName(), requestedIds);
setResourceProperty(resource, ALERT_DEF_COMPONENT_NAME, entity.getComponentName(), requestedIds);
setResourceProperty(resource, ALERT_DEF_ENABLED, Boolean.valueOf(entity.getEnabled()), requestedIds);
setResourceProperty(resource, ALERT_DEF_IGNORE_HOST, Boolean.valueOf(entity.isHostIgnored()), requestedIds);
setResourceProperty(resource, ALERT_DEF_SCOPE, entity.getScope(), requestedIds);
setResourceProperty(resource, ALERT_DEF_HELP_URL, entity.getHelpURL(), requestedIds);
setResourceProperty(resource, ALERT_DEF_REPEAT_TOLERANCE, entity.getRepeatTolerance(), requestedIds);
setResourceProperty(resource, ALERT_DEF_REPEAT_TOLERANCE_ENABLED, Boolean.valueOf(entity.isRepeatToleranceEnabled()), requestedIds);
boolean sourceTypeRequested = setResourceProperty(resource,
ALERT_DEF_SOURCE_TYPE, entity.getSourceType(), requestedIds);
if (sourceTypeRequested
&& null != resource.getPropertyValue(ALERT_DEF_SOURCE_TYPE)) {
try {
Map<String, String> map = gson.<Map<String, String>> fromJson(
entity.getSource(), Map.class);
for (Entry<String, String> entry : map.entrySet()) {
String subProp = PropertyHelper.getPropertyId(ALERT_DEF_SOURCE, entry.getKey());
resource.setProperty(subProp, entry.getValue());
}
} catch (Exception e) {
LOG.error("Could not coerce alert JSON into a type");
}
}
return resource;
}
/**
* Extracts an {@link AlertDefinitionEntity} from the property map and
* enqueues an {@link AlertExecutionCommand} for every host that should re-run
* the specified definition.
*
* @param propertyMap
*/
private void scheduleImmediateAlert(Map<String, Object> propertyMap) throws AuthorizationException {
Clusters clusters = getManagementController().getClusters();
String stringId = (String) propertyMap.get(ALERT_DEF_ID);
long id = Long.parseLong(stringId);
AlertDefinitionEntity entity = alertDefinitionDAO.findById(id);
if (null == entity) {
LOG.error("Unable to lookup alert definition with ID {}", id);
return;
}
Cluster cluster = null;
try {
cluster = clusters.getClusterById(entity.getClusterId());
} catch (AmbariException ambariException) {
LOG.error("Unable to lookup cluster with ID {}", entity.getClusterId(),
ambariException);
return;
}
AlertResourceProviderUtils.verifyExecuteAuthorization(entity);
Set<String> hostNames = alertDefinitionHash.getAssociatedHosts(cluster,
entity.getSourceType(),
entity.getDefinitionName(), entity.getServiceName(),
entity.getComponentName());
for (String hostName : hostNames) {
AlertDefinition definition = definitionFactory.coerce(entity);
AlertExecutionCommand command = new AlertExecutionCommand(
cluster.getClusterName(), hostName, definition);
actionQueue.enqueue(hostName, command);
}
}
}