AMBARI-7021 - Alerts: Create Group and Target REST Endpoints (jonathanhurley)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/4a4644b8 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/4a4644b8 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/4a4644b8 Branch: refs/heads/trunk Commit: 4a4644b882c9a0d39b249db5a106f7075cb0c93d Parents: 6ba11a2 Author: Jonathan Hurley <jhur...@hortonworks.com> Authored: Tue Aug 26 14:21:31 2014 -0400 Committer: Jonathan Hurley <jhur...@hortonworks.com> Committed: Wed Aug 27 08:51:49 2014 -0400 ---------------------------------------------------------------------- .../python/ambari_agent/alerts/base_alert.py | 4 +- .../python/ambari_agent/alerts/port_alert.py | 11 +- .../ambari/server/agent/HeartBeatHandler.java | 16 +- .../resources/AlertGroupResourceDefinition.java | 50 +++ .../AlertTargetResourceDefinition.java | 50 +++ .../resources/ResourceInstanceFactoryImpl.java | 8 + .../server/api/services/AlertGroupService.java | 111 ++++++ .../server/api/services/AlertTargetService.java | 96 ++++++ .../server/api/services/ClusterService.java | 66 +++- .../ambari/server/controller/AmbariServer.java | 4 + .../AbstractControllerResourceProvider.java | 10 +- .../internal/AlertGroupResourceProvider.java | 268 +++++++++++++++ .../internal/AlertTargetResourceProvider.java | 258 ++++++++++++++ .../ambari/server/controller/spi/Resource.java | 13 +- .../ambari/server/orm/dao/AlertDispatchDAO.java | 78 +++-- .../ambari/server/state/alert/AlertGroup.java | 124 +++++++ .../ambari/server/state/alert/AlertTarget.java | 123 +++++++ .../ambari/server/state/alert/TargetType.java | 37 ++ .../svccomphost/ServiceComponentHostImpl.java | 2 + .../src/main/resources/key_properties.json | 7 + .../src/main/resources/properties.json | 18 +- .../AlertGroupResourceProviderTest.java | 335 +++++++++++++++++++ .../AlertTargetResourceProviderTest.java | 290 ++++++++++++++++ .../svccomphost/ServiceComponentHostTest.java | 242 +++++++------- 24 files changed, 2045 insertions(+), 176 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py ---------------------------------------------------------------------- diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py index 07987d9..88c7f92 100644 --- a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py +++ b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py @@ -34,7 +34,7 @@ class BaseAlert(object): self.alert_meta = alert_meta self.alert_source_meta = alert_source_meta self.cluster = '' - self.hostname = '' + self.hostName = '' self._lookup_keys = [] @@ -54,7 +54,7 @@ class BaseAlert(object): def set_cluster(self, cluster, host): ''' sets cluster information for the alert ''' self.cluster = cluster - self.hostname = host + self.hostName = host def collect(self): ''' method used for collection. defers to _collect() ''' http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py ---------------------------------------------------------------------- diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py b/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py index d06d1f4..eaf744a 100644 --- a/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py +++ b/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py @@ -22,7 +22,6 @@ import logging import re import socket import time -import traceback from alerts.base_alert import BaseAlert from resource_management.libraries.functions.get_port_from_url import get_port_from_url @@ -40,7 +39,7 @@ class PortAlert(BaseAlert): def _collect(self): urivalue = self._lookup_property_value(self.uri) - host = get_host_from_url(urivalue) + host = get_host_from_url(self, urivalue) port = self.port try: @@ -76,9 +75,9 @@ Tested on the following cases: "hdfs://192.168.54.3/foo/bar" "ftp://192.168.54.4:7842/foo/bar" ''' -def get_host_from_url(uri): +def get_host_from_url(self, uri): # RFC3986, Appendix B - parts = re.findall('^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?' , uri) + parts = re.findall('^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?', uri) # index of parts # scheme = 1 @@ -96,6 +95,10 @@ def get_host_from_url(uri): host_and_port = parts[0][3] if -1 == host_and_port.find(':'): + # if no : then it might only be a port; if it's a port, return this host + if host_and_port.isdigit(): + return self.hostName + return host_and_port else: return host_and_port.split(':')[0] http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java index dca3bd9..d0d5a13 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java @@ -229,11 +229,13 @@ public class HeartBeatHandler { protected void calculateHostAlerts(HeartBeat heartbeat, String hostname) throws AmbariException { - if (heartbeat != null && hostname != null) { - for (Cluster cluster : clusterFsm.getClustersForHost(hostname)) { - cluster.addAlerts(heartbeat.getNodeStatus().getAlerts()); - } - } + if (null == hostname || null == heartbeat) { + return; + } + + for (Cluster cluster : clusterFsm.getClustersForHost(hostname)) { + cluster.addAlerts(heartbeat.getNodeStatus().getAlerts()); + } } protected void processHostStatus(HeartBeat heartbeat, String hostname) throws AmbariException { @@ -710,7 +712,7 @@ public class HeartBeatHandler { response.setResponseStatus(RegistrationStatus.OK); // force the registering agent host to receive its list of alert definitions - List<AlertDefinitionCommand> alertDefinitionCommands = getAlertDefinitionCommands(hostname); + List<AlertDefinitionCommand> alertDefinitionCommands = getRegistrationAlertDefinitionCommands(hostname); response.setAlertDefinitionCommands(alertDefinitionCommands); Long requestId = 0L; @@ -787,7 +789,7 @@ public class HeartBeatHandler { * @return * @throws AmbariException */ - private List<AlertDefinitionCommand> getAlertDefinitionCommands( + private List<AlertDefinitionCommand> getRegistrationAlertDefinitionCommands( String hostname) throws AmbariException { Set<Cluster> hostClusters = clusterFsm.getClustersForHost(hostname); http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertGroupResourceDefinition.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertGroupResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertGroupResourceDefinition.java new file mode 100644 index 0000000..67e5d60 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertGroupResourceDefinition.java @@ -0,0 +1,50 @@ +/** + * 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.api.resources; + +import org.apache.ambari.server.controller.spi.Resource; + +/** + * The {@link AlertGroupResourceDefinition} class is used to register alert + * groups to be returned via the REST API. + */ +public class AlertGroupResourceDefinition extends BaseResourceDefinition { + + /** + * Constructor. + */ + public AlertGroupResourceDefinition() { + super(Resource.Type.AlertGroup); + } + + /** + * + */ + @Override + public String getPluralName() { + return "alert_groups"; + } + + /** + * + */ + @Override + public String getSingularName() { + return "alert_group"; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertTargetResourceDefinition.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertTargetResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertTargetResourceDefinition.java new file mode 100644 index 0000000..bc0d81d --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertTargetResourceDefinition.java @@ -0,0 +1,50 @@ +/** + * 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.api.resources; + +import org.apache.ambari.server.controller.spi.Resource; + +/** + * The {@link AlertTargetResourceDefinition} class is used to register alert + * targets to be returned via the REST API. + */ +public class AlertTargetResourceDefinition extends BaseResourceDefinition { + + /** + * Constructor. + */ + public AlertTargetResourceDefinition() { + super(Resource.Type.AlertTarget); + } + + /** + * + */ + @Override + public String getPluralName() { + return "alert_targets"; + } + + /** + * + */ + @Override + public String getSingularName() { + return "alert_target"; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java index 13fff1d..7faf365 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java @@ -251,6 +251,14 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory { resourceDefinition = new AlertDefResourceDefinition(); break; + case AlertGroup: + resourceDefinition = new AlertGroupResourceDefinition(); + break; + + case AlertTarget: + resourceDefinition = new AlertTargetResourceDefinition(); + break; + case AmbariPrivilege: resourceDefinition = new PrivilegeResourceDefinition(Resource.Type.AmbariPrivilege); break; http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java new file mode 100644 index 0000000..c2e5048 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java @@ -0,0 +1,111 @@ +/** + * 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.api.services; + +import java.util.HashMap; +import java.util.Map; + +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.apache.ambari.server.api.resources.ResourceInstance; +import org.apache.ambari.server.controller.spi.Resource; +import org.apache.ambari.server.state.alert.AlertGroup; + +/** + * The {@link AlertGroupService} handles CRUD operations for a cluster's alert + * groups. + */ +public class AlertGroupService extends BaseService { + + /** + * Cluster name for cluster-based requests + */ + private String m_clusterName = null; + + /** + * Constructor. + * + * @param clusterName + */ + AlertGroupService(String clusterName) { + m_clusterName = clusterName; + } + + @GET + @Produces("text/plain") + public Response getGroups(String body, @Context HttpHeaders headers, + @Context UriInfo ui) { + return handleRequest(headers, body, ui, Request.Type.GET, + createAlertGroupResource(m_clusterName, null)); + } + + @GET + @Produces("text/plain") + @Path("{groupId}") + public Response getGroup(String body, @Context HttpHeaders headers, + @Context UriInfo ui, @PathParam("groupId") Long groupId) { + return handleRequest(headers, body, ui, Request.Type.GET, + createAlertGroupResource(m_clusterName, groupId)); + } + + @POST + @Produces("text/plain") + public Response createGroup(String body, @Context HttpHeaders headers, + @Context UriInfo ui) { + return handleRequest(headers, body, ui, Request.Type.POST, + createAlertGroupResource(m_clusterName, null)); + } + + @DELETE + @Produces("text/plain") + @Path("{groupId}") + public Response deleteGroup(String body, @Context HttpHeaders headers, + @Context UriInfo ui, @PathParam("groupId") Long groupId) { + return handleRequest(headers, body, ui, Request.Type.DELETE, + createAlertGroupResource(m_clusterName, groupId)); + } + + /** + * Create a request capturing the group ID and resource type for an + * {@link AlertGroup}. + * + * @param groupId + * the unique ID of the group to create the query for (not + * {@code null}). + * @return the instance of the query. + */ + private ResourceInstance createAlertGroupResource(String clusterName, + Long groupId) { + + Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>(); + mapIds.put(Resource.Type.Cluster, m_clusterName); + mapIds.put(Resource.Type.AlertGroup, + null == groupId ? null : groupId.toString()); + + return createResource(Resource.Type.AlertGroup, mapIds); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java new file mode 100644 index 0000000..86281b3 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java @@ -0,0 +1,96 @@ +/** + * 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.api.services; + +import java.util.HashMap; +import java.util.Map; + +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.apache.ambari.server.api.resources.ResourceInstance; +import org.apache.ambari.server.controller.spi.Resource; +import org.apache.ambari.server.state.alert.AlertTarget; + +/** + * The {@link AlertTargetService} handles CRUD operation requests for alert + * targets. + */ +@Path("/alert_targets/") +public class AlertTargetService extends BaseService { + + @GET + @Produces("text/plain") + public Response getTargets(String body, @Context HttpHeaders headers, + @Context UriInfo ui) { + return handleRequest(headers, body, ui, Request.Type.GET, + createAlertTargetResource(null)); + } + + @GET + @Produces("text/plain") + @Path("{targetId}") + public Response getTargets(String body, @Context HttpHeaders headers, + @Context UriInfo ui, @PathParam("targetId") Long targetId) { + return handleRequest(headers, body, ui, Request.Type.GET, + createAlertTargetResource(targetId)); + } + + @POST + @Produces("text/plain") + public Response createTarget(String body, @Context HttpHeaders headers, + @Context UriInfo ui) { + return handleRequest(headers, body, ui, Request.Type.POST, + createAlertTargetResource(null)); + } + + @DELETE + @Produces("text/plain") + @Path("{targetId}") + public Response deleteTarget(String body, @Context HttpHeaders headers, + @Context UriInfo ui, @PathParam("targetId") Long targetId) { + return handleRequest(headers, body, ui, Request.Type.DELETE, + createAlertTargetResource(targetId)); + } + + /** + * Create a request capturing the target ID and resource type for an + * {@link AlertTarget}. + * + * @param targetId + * the unique ID of the target to create the query for (not + * {@code null}). + * @return the instance of the query. + */ + private ResourceInstance createAlertTargetResource(Long targetId) { + Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>(); + + mapIds.put(Resource.Type.AlertTarget, + null == targetId ? null : targetId.toString()); + + return createResource(Resource.Type.AlertTarget, mapIds); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java index 8043b3f..3f1ce36 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java @@ -18,15 +18,26 @@ package org.apache.ambari.server.api.services; +import java.util.Collections; + +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + import org.apache.ambari.server.api.resources.ResourceInstance; import org.apache.ambari.server.controller.AmbariServer; import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.state.Clusters; -import javax.ws.rs.*; -import javax.ws.rs.core.*; -import java.util.Collections; - /** * Service responsible for cluster resource requests. @@ -46,7 +57,7 @@ public class ClusterService extends BaseService { * Construct a ClusterService. */ public ClusterService() { - this.clusters = AmbariServer.getController().getClusters(); + clusters = AmbariServer.getController().getClusters(); } /** @@ -187,7 +198,7 @@ public class ClusterService extends BaseService { hasPermission(Request.Type.valueOf(request.getMethod()), clusterName); return new ServiceService(clusterName); } - + /** * Gets the configurations sub-resource. * @@ -295,7 +306,7 @@ public class ClusterService extends BaseService { hasPermission(Request.Type.valueOf(request.getMethod()), clusterName); return new RequestScheduleService(clusterName); } - + /** * Gets the alert definition service * @@ -313,12 +324,32 @@ public class ClusterService extends BaseService { } /** + * Gets the alert group service. + * + * @param request + * the request. + * @param clusterName + * the cluster name. + * @return the alert group service. + */ + @Path("{clusterName}/alert_groups") + public AlertGroupService getAlertGroups( + @Context javax.ws.rs.core.Request request, + @PathParam("clusterName") String clusterName) { + + hasPermission(Request.Type.valueOf(request.getMethod()), clusterName); + return new AlertGroupService(clusterName); + } + + /** * Gets the privilege service * - * @param request the request - * @param clusterName the cluster name + * @param request + * the request + * @param clusterName + * the cluster name * - * @return the privileges service + * @return the privileges service */ @Path("{clusterName}/privileges") public PrivilegeService getPrivilegeService(@Context javax.ws.rs.core.Request request, @PathParam ("clusterName") String clusterName) { @@ -343,14 +374,17 @@ public class ClusterService extends BaseService { } /** - * Determine whether or not the access specified by the given request type - * is permitted for the current user on the cluster resource identified by - * the given cluster name. + * Determine whether or not the access specified by the given request type is + * permitted for the current user on the cluster resource identified by the + * given cluster name. * - * @param requestType the request method type - * @param clusterName the name of the cluster resource + * @param requestType + * the request method type + * @param clusterName + * the name of the cluster resource * - * @throws WebApplicationException if access is forbidden + * @throws WebApplicationException + * if access is forbidden */ private void hasPermission(Request.Type requestType, String clusterName) throws WebApplicationException { if (!clusters.checkPermission(clusterName, requestType == Request.Type.GET)) { http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java index 21c9d80..c75a7bb 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java @@ -46,6 +46,8 @@ import org.apache.ambari.server.configuration.ComponentSSLConfiguration; import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.controller.internal.AbstractControllerResourceProvider; import org.apache.ambari.server.controller.internal.AlertDefinitionResourceProvider; +import org.apache.ambari.server.controller.internal.AlertGroupResourceProvider; +import org.apache.ambari.server.controller.internal.AlertTargetResourceProvider; import org.apache.ambari.server.controller.internal.AmbariPrivilegeResourceProvider; import org.apache.ambari.server.controller.internal.BlueprintResourceProvider; import org.apache.ambari.server.controller.internal.ClusterPrivilegeResourceProvider; @@ -538,6 +540,8 @@ public class AmbariServer { StackDependencyResourceProvider.init(ambariMetaInfo); ClusterResourceProvider.init(injector.getInstance(BlueprintDAO.class), ambariMetaInfo, injector.getInstance(ConfigHelper.class)); AlertDefinitionResourceProvider.init(injector); + AlertGroupResourceProvider.init(injector); + AlertTargetResourceProvider.init(injector); PermissionResourceProvider.init(injector.getInstance(PermissionDAO.class)); ViewPermissionResourceProvider.init(injector.getInstance(PermissionDAO.class)); PrivilegeResourceProvider.init(injector.getInstance(PrivilegeDAO.class), injector.getInstance(UserDAO.class), http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java index 71ddc8d..c10d300 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java @@ -18,15 +18,15 @@ package org.apache.ambari.server.controller.internal; +import java.util.Map; +import java.util.Set; + import org.apache.ambari.server.controller.AmbariManagementController; import org.apache.ambari.server.controller.ResourceProviderFactory; import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.controller.spi.ResourceProvider; import org.apache.ambari.server.controller.utilities.ClusterControllerHelper; -import java.util.Map; -import java.util.Set; - /** * Abstract resource provider implementation that maps to an Ambari management controller. */ @@ -149,6 +149,10 @@ public abstract class AbstractControllerResourceProvider extends AbstractResourc return new ValidationResourceProvider(propertyIds, keyPropertyIds, managementController); case AlertDefinition: return new AlertDefinitionResourceProvider(propertyIds, keyPropertyIds, managementController); + case AlertGroup: + return new AlertGroupResourceProvider(propertyIds, keyPropertyIds, managementController); + case AlertTarget: + return new AlertTargetResourceProvider(propertyIds, keyPropertyIds, managementController); case Controller: return new ControllerResourceProvider(propertyIds, keyPropertyIds, managementController); case ClientConfig: http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java new file mode 100644 index 0000000..f14e76f --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java @@ -0,0 +1,268 @@ +/** + * 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.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.ambari.server.AmbariException; +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.Resource.Type; +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.orm.dao.AlertDispatchDAO; +import org.apache.ambari.server.orm.entities.AlertGroupEntity; +import org.apache.ambari.server.orm.entities.AlertTargetEntity; +import org.apache.ambari.server.state.Cluster; +import org.apache.ambari.server.state.alert.AlertGroup; +import org.apache.commons.lang.StringUtils; + +import com.google.inject.Inject; +import com.google.inject.Injector; + +/** + * The {@link AlertGroupResourceProvider} class deals with managing the CRUD + * operations for {@link AlertGroup}, including property coercion to and from + * {@link AlertGroupEntity}. + */ +public class AlertGroupResourceProvider extends + AbstractControllerResourceProvider { + + protected static final String ALERT_GROUP = "AlertGroup"; + protected static final String ALERT_GROUP_ID = "AlertGroup/id"; + protected static final String ALERT_GROUP_CLUSTER_NAME = "AlertGroup/cluster_name"; + protected static final String ALERT_GROUP_NAME = "AlertGroup/name"; + protected static final String ALERT_GROUP_DEFAULT = "AlertGroup/default"; + protected static final String ALERT_GROUP_DEFINITIONS = "AlertGroup/definitions"; + protected static final String ALERT_GROUP_TARGETS = "AlertGroup/targets"; + + private static final Set<String> PK_PROPERTY_IDS = new HashSet<String>( + Arrays.asList(ALERT_GROUP_ID, ALERT_GROUP_CLUSTER_NAME)); + + /** + * Group DAO + */ + @Inject + private static AlertDispatchDAO s_dao; + + /** + * Initializes the injectable members of this class with the specified + * injector. + * + * @param injector + * the injector (not {@code null}). + */ + @Inject + public static void init(Injector injector) { + s_dao = injector.getInstance(AlertDispatchDAO.class); + } + + /** + * Constructor. + * + * @param propertyIds + * @param keyPropertyIds + * @param managementController + */ + AlertGroupResourceProvider(Set<String> propertyIds, + Map<Type, String> keyPropertyIds, + AmbariManagementController managementController) { + super(propertyIds, keyPropertyIds, managementController); + } + + @Override + public RequestStatus createResources(final Request request) + throws SystemException, + UnsupportedPropertyException, ResourceAlreadyExistsException, + NoSuchParentResourceException { + + createResources(new Command<Void>() { + @Override + public Void invoke() throws AmbariException { + createAlertGroups(request.getProperties()); + return null; + } + }); + + notifyCreate(Resource.Type.AlertGroup, request); + return getRequestStatus(null); + } + + @Override + public Set<Resource> getResources(Request request, Predicate predicate) + throws SystemException, UnsupportedPropertyException, + NoSuchResourceException, NoSuchParentResourceException { + + Set<Resource> results = new HashSet<Resource>(); + Set<String> requestPropertyIds = getRequestPropertyIds(request, predicate); + + for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) { + String clusterName = (String) propertyMap.get(ALERT_GROUP_CLUSTER_NAME); + + if (null == clusterName || clusterName.isEmpty()) { + throw new IllegalArgumentException("The cluster name is required when retrieving alert groups"); + } + + String id = (String) propertyMap.get(ALERT_GROUP_ID); + if (null != id) { + AlertGroupEntity entity = s_dao.findGroupById(Long.parseLong(id)); + if (null != entity) { + results.add(toResource(false, clusterName, entity, requestPropertyIds)); + } + } else { + Cluster cluster = null; + + try { + cluster = getManagementController().getClusters().getCluster(clusterName); + } catch (AmbariException ae) { + throw new NoSuchResourceException("Parent Cluster resource doesn't exist", ae); + } + + List<AlertGroupEntity> entities = s_dao.findAllGroups(cluster.getClusterId()); + + for (AlertGroupEntity entity : entities) { + results.add(toResource(true, clusterName, entity, requestPropertyIds)); + } + } + } + + return results; + } + + @Override + public RequestStatus updateResources(Request request, Predicate predicate) + throws SystemException, UnsupportedPropertyException, + NoSuchResourceException, NoSuchParentResourceException { + + throw new UnsupportedOperationException(); + } + + @Override + public RequestStatus deleteResources(Predicate predicate) + throws SystemException, UnsupportedPropertyException, + NoSuchResourceException, NoSuchParentResourceException { + + Set<Resource> resources = getResources(new RequestImpl(null, null, null, + null), predicate); + + Set<Long> groupIds = new HashSet<Long>(); + + for (final Resource resource : resources) { + Long id = (Long) resource.getPropertyValue(ALERT_GROUP_ID); + groupIds.add(id); + } + + for (Long groupId : groupIds) { + LOG.info("Deleting alert target {}", groupId); + + final AlertGroupEntity entity = s_dao.findGroupById(groupId.longValue()); + + modifyResources(new Command<Void>() { + @Override + public Void invoke() throws AmbariException { + s_dao.remove(entity); + return null; + } + }); + } + + notifyDelete(Resource.Type.AlertGroup, predicate); + return getRequestStatus(null); + } + + @Override + protected Set<String> getPKPropertyIds() { + return PK_PROPERTY_IDS; + } + + /** + * Create and persist {@link AlertTargetEntity} from the map of properties. + * + * @param requestMaps + * @throws AmbariException + */ + private void createAlertGroups(Set<Map<String, Object>> requestMaps) + throws AmbariException { + + List<AlertGroupEntity> entities = new ArrayList<AlertGroupEntity>(); + for (Map<String, Object> requestMap : requestMaps) { + AlertGroupEntity entity = new AlertGroupEntity(); + + String name = (String) requestMap.get(ALERT_GROUP_NAME); + String clusterName = (String) requestMap.get(ALERT_GROUP_CLUSTER_NAME); + + if (StringUtils.isEmpty(name)) { + throw new IllegalArgumentException( + "The name of the alert group is required."); + } + + if (StringUtils.isEmpty(clusterName)) { + throw new IllegalArgumentException( + "The name of the cluster is required when creating an alert group."); + } + + Cluster cluster = getManagementController().getClusters().getCluster( + clusterName); + + entity.setClusterId(cluster.getClusterId()); + entity.setDefault(false); + entity.setGroupName(name); + + entities.add(entity); + } + + s_dao.createGroups(entities); + } + + /** + * Convert the given {@link AlertGroupEntity} to a {@link Resource}. + * + * @param isCollection + * {@code true} if the resource is part of a collection. + * @param entity + * the entity to convert. + * @param requestedIds + * the properties that were requested or {@code null} for all. + * @return the resource representation of the entity (never {@code null}). + */ + private Resource toResource(boolean isCollection, String clusterName, + AlertGroupEntity entity, + Set<String> requestedIds) { + + Resource resource = new ResourceImpl(Resource.Type.AlertGroup); + resource.setProperty(ALERT_GROUP_ID, entity.getGroupId()); + resource.setProperty(ALERT_GROUP_NAME, entity.getGroupName()); + resource.setProperty(ALERT_GROUP_CLUSTER_NAME, clusterName); + + setResourceProperty(resource, ALERT_GROUP_DEFAULT, + entity.isDefault(), requestedIds); + + return resource; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java new file mode 100644 index 0000000..e00f60f --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java @@ -0,0 +1,258 @@ +/** + * 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.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.ambari.server.AmbariException; +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.Resource.Type; +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.orm.dao.AlertDispatchDAO; +import org.apache.ambari.server.orm.entities.AlertTargetEntity; +import org.apache.ambari.server.state.alert.AlertTarget; +import org.apache.commons.lang.StringUtils; + +import com.google.inject.Inject; +import com.google.inject.Injector; + +/** + * The {@link AlertTargetResourceProvider} class deals with managing the CRUD + * operations for {@link AlertTarget}, including property coercion to and from + * {@link AlertTargetEntity}. + */ +public class AlertTargetResourceProvider extends + AbstractControllerResourceProvider { + + protected static final String ALERT_TARGET = "AlertTarget"; + protected static final String ALERT_TARGET_ID = "AlertTarget/id"; + protected static final String ALERT_TARGET_NAME = "AlertTarget/name"; + protected static final String ALERT_TARGET_DESCRIPTION = "AlertTarget/description"; + protected static final String ALERT_TARGET_NOTIFICATION_TYPE = "AlertTarget/notification_type"; + protected static final String ALERT_TARGET_PROPERTIES = "AlertTarget/properties"; + protected static final String ALERT_TARGET_GROUPS = "AlertTarget/groups"; + + private static final Set<String> PK_PROPERTY_IDS = new HashSet<String>( + Arrays.asList(ALERT_TARGET_ID, ALERT_TARGET_NAME)); + + /** + * Target DAO + */ + @Inject + private static AlertDispatchDAO s_dao; + + /** + * Initializes the injectable members of this class with the specified + * injector. + * + * @param injector + * the injector (not {@code null}). + */ + @Inject + public static void init(Injector injector) { + s_dao = injector.getInstance(AlertDispatchDAO.class); + } + + /** + * Constructor. + * + * @param propertyIds + * @param keyPropertyIds + * @param managementController + */ + AlertTargetResourceProvider(Set<String> propertyIds, + Map<Type, String> keyPropertyIds, + AmbariManagementController managementController) { + super(propertyIds, keyPropertyIds, managementController); + } + + @Override + public RequestStatus createResources(final Request request) + throws SystemException, + UnsupportedPropertyException, ResourceAlreadyExistsException, + NoSuchParentResourceException { + + createResources(new Command<Void>() { + @Override + public Void invoke() throws AmbariException { + createAlertTargets(request.getProperties()); + return null; + } + }); + + notifyCreate(Resource.Type.AlertTarget, request); + return getRequestStatus(null); + } + + @Override + public Set<Resource> getResources(Request request, Predicate predicate) + throws SystemException, UnsupportedPropertyException, + NoSuchResourceException, NoSuchParentResourceException { + + Set<Resource> results = new HashSet<Resource>(); + Set<String> requestPropertyIds = getRequestPropertyIds(request, predicate); + + if( null == predicate ){ + List<AlertTargetEntity> entities = s_dao.findAllTargets(); + for (AlertTargetEntity entity : entities) { + results.add(toResource(true, entity, requestPropertyIds)); + } + } else { + for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) { + String id = (String) propertyMap.get(ALERT_TARGET_ID); + if (null == id) { + continue; + } + + AlertTargetEntity entity = s_dao.findTargetById(Long.parseLong(id)); + if (null != entity) { + results.add(toResource(false, entity, requestPropertyIds)); + } + } + } + + return results; + } + + @Override + public RequestStatus updateResources(Request request, Predicate predicate) + throws SystemException, UnsupportedPropertyException, + NoSuchResourceException, NoSuchParentResourceException { + + throw new UnsupportedOperationException(); + } + + @Override + public RequestStatus deleteResources(Predicate predicate) + throws SystemException, UnsupportedPropertyException, + NoSuchResourceException, NoSuchParentResourceException { + + Set<Resource> resources = getResources(new RequestImpl(null, null, null, + null), predicate); + + Set<Long> targetIds = new HashSet<Long>(); + + for (final Resource resource : resources) { + Long id = (Long) resource.getPropertyValue(ALERT_TARGET_ID); + targetIds.add(id); + } + + for (Long targetId : targetIds) { + LOG.info("Deleting alert target {}", targetId); + + final AlertTargetEntity entity = s_dao.findTargetById(targetId.longValue()); + + modifyResources(new Command<Void>() { + @Override + public Void invoke() throws AmbariException { + s_dao.remove(entity); + return null; + } + }); + } + + notifyDelete(Resource.Type.AlertTarget, predicate); + return getRequestStatus(null); + } + + @Override + protected Set<String> getPKPropertyIds() { + return PK_PROPERTY_IDS; + } + + /** + * Create and persist {@link AlertTargetEntity} from the map of properties. + * + * @param requestMaps + * @throws AmbariException + */ + private void createAlertTargets(Set<Map<String, Object>> requestMaps) + throws AmbariException { + List<AlertTargetEntity> entities = new ArrayList<AlertTargetEntity>(); + for (Map<String, Object> requestMap : requestMaps) { + AlertTargetEntity entity = new AlertTargetEntity(); + + String name = (String) requestMap.get(ALERT_TARGET_NAME); + String description = (String) requestMap.get(ALERT_TARGET_DESCRIPTION); + String notificationType = (String) requestMap.get(ALERT_TARGET_NOTIFICATION_TYPE); + String properties = (String) requestMap.get(ALERT_TARGET_PROPERTIES); + + if (StringUtils.isEmpty(name)) { + throw new IllegalArgumentException( + "The name of the alert target is required."); + } + + if (StringUtils.isEmpty(notificationType)) { + throw new IllegalArgumentException( + "The type of the alert target is required."); + } + + entity.setDescription(description); + entity.setNotificationType(notificationType); + entity.setProperties(properties); + entity.setTargetName(name); + + entities.add(entity); + } + + s_dao.createTargets(entities); + } + + /** + * Convert the given {@link AlertTargetEntity} to a {@link Resource}. + * + * @param isCollection + * {@code true} if the resource is part of a collection. + * @param entity + * the entity to convert. + * @param requestedIds + * the properties that were requested or {@code null} for all. + * @return the resource representation of the entity (never {@code null}). + */ + private Resource toResource(boolean isCollection, AlertTargetEntity entity, + Set<String> requestedIds) { + + Resource resource = new ResourceImpl(Resource.Type.AlertTarget); + resource.setProperty(ALERT_TARGET_ID, entity.getTargetId()); + resource.setProperty(ALERT_TARGET_NAME, entity.getTargetName()); + + setResourceProperty(resource, ALERT_TARGET_DESCRIPTION, + entity.getDescription(), requestedIds); + + setResourceProperty(resource, ALERT_TARGET_NOTIFICATION_TYPE, + entity.getNotificationType(), requestedIds); + + setResourceProperty(resource, ALERT_TARGET_PROPERTIES, + entity.getProperties(), requestedIds); + + return resource; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java index b10b4bc..3114809 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java @@ -115,6 +115,8 @@ public interface Resource { HostComponentProcess, Permission, AlertDefinition, + AlertGroup, + AlertTarget, AmbariPrivilege, ClusterPrivilege, ViewPrivilege, @@ -196,6 +198,8 @@ public interface Resource { public static final Type HostComponentProcess = InternalType.HostComponentProcess.getType(); public static final Type Permission = InternalType.Permission.getType(); public static final Type AlertDefinition = InternalType.AlertDefinition.getType(); + public static final Type AlertGroup = InternalType.AlertGroup.getType(); + public static final Type AlertTarget = InternalType.AlertTarget.getType(); public static final Type AmbariPrivilege = InternalType.AmbariPrivilege.getType(); public static final Type ClusterPrivilege = InternalType.ClusterPrivilege.getType(); public static final Type ViewPrivilege = InternalType.ViewPrivilege.getType(); @@ -315,8 +319,13 @@ public interface Resource { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } Type type = (Type) o; http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java index 2871e62..dfbe747 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java @@ -51,7 +51,7 @@ public class AlertDispatchDAO { /** * Gets an alert group with the specified ID. - * + * * @param groupId * the ID of the group to retrieve. * @return the group or {@code null} if none exists. @@ -62,7 +62,7 @@ public class AlertDispatchDAO { /** * Gets an alert target with the specified ID. - * + * * @param targetId * the ID of the target to retrieve. * @return the target or {@code null} if none exists. @@ -73,7 +73,7 @@ public class AlertDispatchDAO { /** * Gets a notification with the specified ID. - * + * * @param noticeId * the ID of the notification to retrieve. * @return the notification or {@code null} if none exists. @@ -85,7 +85,7 @@ public class AlertDispatchDAO { /** * Gets an alert group with the specified name across all clusters. Alert * group names are unique within a cluster. - * + * * @param groupName * the name of the group (not {@code null}). * @return the alert group or {@code null} if none exists. @@ -102,7 +102,7 @@ public class AlertDispatchDAO { /** * Gets an alert group with the specified name for the given cluster. Alert * group names are unique within a cluster. - * + * * @param clusterId * the ID of the cluster. * @param groupName @@ -122,7 +122,7 @@ public class AlertDispatchDAO { /** * Gets an alert target with the specified name. Alert target names are unique * across all clusters. - * + * * @param targetName * the name of the target (not {@code null}). * @return the alert target or {@code null} if none exists. @@ -138,7 +138,7 @@ public class AlertDispatchDAO { /** * Gets all alert groups stored in the database across all clusters. - * + * * @return all alert groups or empty list if none exist (never {@code null}). */ public List<AlertGroupEntity> findAllGroups() { @@ -150,7 +150,7 @@ public class AlertDispatchDAO { /** * Gets all alert groups stored in the database for the specified cluster. - * + * * @return all alert groups in the specified cluster or empty list if none * exist (never {@code null}). */ @@ -165,7 +165,7 @@ public class AlertDispatchDAO { /** * Gets all alert targets stored in the database. - * + * * @return all alert targets or empty list if none exist (never {@code null}). */ public List<AlertTargetEntity> findAllTargets() { @@ -177,7 +177,7 @@ public class AlertDispatchDAO { /** * Gets all alert notifications stored in the database. - * + * * @return all alert notifications or empty list if none exist (never * {@code null}). */ @@ -189,6 +189,23 @@ public class AlertDispatchDAO { } /** + * Persists new alert groups. + * + * @param entities + * the groups to persist (not {@code null}). + */ + @Transactional + public void createGroups(List<AlertGroupEntity> entities) { + if (null == entities) { + return; + } + + for (AlertGroupEntity entity : entities) { + create(entity); + } + } + + /** * Persists a new alert group. * * @param alertGroup @@ -201,7 +218,7 @@ public class AlertDispatchDAO { /** * Refresh the state of the alert group from the database. - * + * * @param alertGroup * the group to refresh (not {@code null}). */ @@ -212,7 +229,7 @@ public class AlertDispatchDAO { /** * Merge the speicified alert group with the existing group in the database. - * + * * @param alertGroup * the group to merge (not {@code null}). * @return the updated group with merged content (never {@code null}). @@ -224,7 +241,7 @@ public class AlertDispatchDAO { /** * Removes the specified alert group from the database. - * + * * @param alertGroup * the group to remove. */ @@ -234,8 +251,25 @@ public class AlertDispatchDAO { } /** + * Persists new alert targets. + * + * @param entities + * the targets to persist (not {@code null}). + */ + @Transactional + public void createTargets(List<AlertTargetEntity> entities) { + if (null == entities) { + return; + } + + for (AlertTargetEntity entity : entities) { + create(entity); + } + } + + /** * Persists a new alert target. - * + * * @param alertTarget * the target to persist (not {@code null}). */ @@ -246,7 +280,7 @@ public class AlertDispatchDAO { /** * Refresh the state of the alert target from the database. - * + * * @param alertTarget * the target to refresh (not {@code null}). */ @@ -257,7 +291,7 @@ public class AlertDispatchDAO { /** * Merge the speicified alert target with the existing target in the database. - * + * * @param alertTarget * the target to merge (not {@code null}). * @return the updated target with merged content (never {@code null}). @@ -269,7 +303,7 @@ public class AlertDispatchDAO { /** * Removes the specified alert target from the database. - * + * * @param alertTarget * the target to remove. */ @@ -280,7 +314,7 @@ public class AlertDispatchDAO { /** * Persists a new notification. - * + * * @param alertNotice * the notification to persist (not {@code null}). */ @@ -291,7 +325,7 @@ public class AlertDispatchDAO { /** * Refresh the state of the notification from the database. - * + * * @param alertNotice * the notification to refresh (not {@code null}). */ @@ -302,7 +336,7 @@ public class AlertDispatchDAO { /** * Merge the specified notification with the existing target in the database. - * + * * @param alertNotice * the notification to merge (not {@code null}). * @return the updated notification with merged content (never {@code null}). @@ -314,7 +348,7 @@ public class AlertDispatchDAO { /** * Removes the specified notification from the database. - * + * * @param alertNotice * the notification to remove. */ @@ -327,7 +361,7 @@ public class AlertDispatchDAO { * Removes notifications for the specified alert definition ID. This will * invoke {@link EntityManager#clear()} when completed since the JPQL * statement will remove entries without going through the EM. - * + * * @param definitionId * the ID of the definition to remove. */ http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertGroup.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertGroup.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertGroup.java new file mode 100644 index 0000000..659efa9 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertGroup.java @@ -0,0 +1,124 @@ +/** + * 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.state.alert; + +import java.util.List; + +/** + * The {@link AlertGroup} class represents a grouping of {@link AlertDefinition} + * instances as well as the targets that will be invoked when an alert is + * triggered. + */ +public class AlertGroup { + private String m_id; + private String m_name; + private String m_clusterName; + private boolean m_isDefault; + private List<AlertDefinition> m_definitions; + private List<AlertTarget> m_targets; + + /** + * @return the id + */ + public String getId() { + return m_id; + } + + /** + * @param id + * the id to set + */ + public void setId(String id) { + m_id = id; + } + + /** + * @return the name + */ + public String getName() { + return m_name; + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + m_name = name; + } + + /** + * @return the clusterName + */ + public String getClusterName() { + return m_clusterName; + } + + /** + * @param clusterName + * the clusterName to set + */ + public void setClusterName(String clusterName) { + m_clusterName = clusterName; + } + + /** + * @return the isDefault + */ + public boolean isDefault() { + return m_isDefault; + } + + /** + * @param isDefault + * the isDefault to set + */ + public void setDefault(boolean isDefault) { + m_isDefault = isDefault; + } + + /** + * @return the definitions + */ + public List<AlertDefinition> getDefinitions() { + return m_definitions; + } + + /** + * @param definitions + * the definitions to set + */ + public void setDefinitions(List<AlertDefinition> definitions) { + m_definitions = definitions; + } + + /** + * @return the targets + */ + public List<AlertTarget> getTargets() { + return m_targets; + } + + /** + * @param targets + * the targets to set + */ + public void setTargets(List<AlertTarget> targets) { + m_targets = targets; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java new file mode 100644 index 0000000..21e83d9 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java @@ -0,0 +1,123 @@ +/** + * 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.state.alert; + +import java.util.List; + +/** + * The {@link AlertTarget} class represents a dispatch mechanism and audience + * that will receive information about alerts int he system. + */ +public class AlertTarget { + private String m_id; + private String m_name; + private String m_description; + private String m_notificationType; + private String m_properties; + private List<AlertGroup> m_groups; + + /** + * @return the id + */ + public String getId() { + return m_id; + } + + /** + * @param id + * the id to set + */ + public void setId(String id) { + m_id = id; + } + + /** + * @return the name + */ + public String getName() { + return m_name; + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + m_name = name; + } + + /** + * @return the description + */ + public String getDescription() { + return m_description; + } + + /** + * @param description + * the description to set + */ + public void setDescription(String description) { + m_description = description; + } + + /** + * @return the notificationType + */ + public String getNotificationType() { + return m_notificationType; + } + + /** + * @param notificationType + * the notificationType to set + */ + public void setNotificationType(String notificationType) { + m_notificationType = notificationType; + } + + /** + * @return the properties + */ + public String getProperties() { + return m_properties; + } + + /** + * @param properties + * the properties to set + */ + public void setProperties(String properties) { + m_properties = properties; + } + + /** + * @return the groups + */ + public List<AlertGroup> getGroups() { + return m_groups; + } + + /** + * @param groups + * the groups to set + */ + public void setGroups(List<AlertGroup> groups) { + m_groups = groups; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/state/alert/TargetType.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/TargetType.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/TargetType.java new file mode 100644 index 0000000..e2564cc --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/TargetType.java @@ -0,0 +1,37 @@ +/** + * 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.state.alert; + +import org.apache.ambari.server.orm.dao.AlertsDAO; + +/** + * The {@link TargetType} enumeration is used to represent the built-in target + * dispatch mechanisms that are supported internally. {@link AlertTarget} + * instances may have other custom target types that are not listed here. + */ +public enum TargetType { + /** + * Alerts will be distributed via email. + */ + EMAIL, + + /** + * {@link AlertsDAO} will be distributed via SNMP. + */ + SNMP; +} http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java index cc5bb5b..75265b7 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java @@ -555,6 +555,8 @@ public class ServiceComponentHostImpl implements ServiceComponentHost { impl.alertDefinitionHash.invalidate(impl.getClusterName(), hostName); impl.alertDefinitionHash.enqueueAgentCommands(impl.getClusterName(), Collections.singleton(hostName)); + + impl.updateLastOpInfo(event.getType(), event.getOpTimestamp()); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/resources/key_properties.json ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/key_properties.json b/ambari-server/src/main/resources/key_properties.json index 06ebb61..3007fee 100644 --- a/ambari-server/src/main/resources/key_properties.json +++ b/ambari-server/src/main/resources/key_properties.json @@ -149,6 +149,13 @@ "Cluster": "AlertDefinition/cluster_name", "AlertDefinition": "AlertDefinition/id" }, + "AlertTarget": { + "AlertTarget": "AlertTarget/id" + }, + "AlertGroup": { + "Cluster": "AlertGroup/cluster_name", + "AlertGroup": "AlertGroup/id" + }, "Controller": { "Controller": "Controllers/name" }, http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/resources/properties.json ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json index bc2ad22..9574aa9 100644 --- a/ambari-server/src/main/resources/properties.json +++ b/ambari-server/src/main/resources/properties.json @@ -425,7 +425,23 @@ "AlertDefinition/enabled", "AlertDefinition/scope", "AlertDefinition/source" - ], + ], + "AlertGroup": [ + "AlertGroup/id", + "AlertGroup/name", + "AlertGroup/cluster_name", + "AlertGroup/default", + "AlertGroup/definitions", + "AlertGroup/targets" + ], + "AlertTarget": [ + "AlertTarget/id", + "AlertTarget/name", + "AlertTarget/description", + "AlertTarget/notification_type", + "AlertTarget/properties", + "AlertTarget/groups" + ], "Controller":[ "Controllers/name", "LDAP/configured", http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java new file mode 100644 index 0000000..c9428b7 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java @@ -0,0 +1,335 @@ +/** + * 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 static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.createStrictMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.resetToStrict; +import static org.easymock.EasyMock.verify; +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.ambari.server.controller.AmbariManagementController; +import org.apache.ambari.server.controller.spi.Predicate; +import org.apache.ambari.server.controller.spi.Request; +import org.apache.ambari.server.controller.spi.Resource; +import org.apache.ambari.server.controller.utilities.PredicateBuilder; +import org.apache.ambari.server.controller.utilities.PropertyHelper; +import org.apache.ambari.server.metadata.ActionMetadata; +import org.apache.ambari.server.orm.InMemoryDefaultTestModule; +import org.apache.ambari.server.orm.dao.AlertDispatchDAO; +import org.apache.ambari.server.orm.entities.AlertGroupEntity; +import org.apache.ambari.server.state.Cluster; +import org.apache.ambari.server.state.Clusters; +import org.easymock.Capture; +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.google.inject.Binder; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Module; +import com.google.inject.util.Modules; + +/** + * {@link AlertGroupResourceProvider} tests. + */ +public class AlertGroupResourceProviderTest { + + private static final Long ALERT_GROUP_ID = Long.valueOf(28); + private static final String ALERT_GROUP_NAME = "Important Alerts"; + private static final long ALERT_GROUP_CLUSTER_ID = 1L; + private static final String ALERT_GROUP_CLUSTER_NAME = "c1"; + + private AlertDispatchDAO m_dao; + private Injector m_injector; + + @Before + public void before() { + m_dao = createStrictMock(AlertDispatchDAO.class); + + m_injector = Guice.createInjector(Modules.override( + new InMemoryDefaultTestModule()).with(new MockModule())); + + AlertGroupResourceProvider.init(m_injector); + } + + /** + * @throws Exception + */ + @Test + public void testGetResourcesNoPredicate() throws Exception { + AlertGroupResourceProvider provider = createProvider(null); + + Request request = PropertyHelper.getReadRequest("AlertGroup/cluster_name", + "AlertGroup/id"); + + Set<Resource> results = provider.getResources(request, null); + + assertEquals(0, results.size()); + } + + /** + * @throws Exception + */ + @Test + public void testGetResourcesClusterPredicate() throws Exception { + Request request = PropertyHelper.getReadRequest( + AlertGroupResourceProvider.ALERT_GROUP_ID, + AlertGroupResourceProvider.ALERT_GROUP_NAME, + AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME, + AlertGroupResourceProvider.ALERT_GROUP_DEFAULT); + + AmbariManagementController amc = createMock(AmbariManagementController.class); + Clusters clusters = createMock(Clusters.class); + Cluster cluster = createMock(Cluster.class); + expect(amc.getClusters()).andReturn(clusters).atLeastOnce(); + expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce(); + expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes(); + + Predicate predicate = new PredicateBuilder().property( + AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME).equals("c1").toPredicate(); + + expect(m_dao.findAllGroups(ALERT_GROUP_CLUSTER_ID)).andReturn( + getMockEntities()); + + replay(amc, clusters, cluster, m_dao); + + AlertGroupResourceProvider provider = createProvider(amc); + Set<Resource> results = provider.getResources(request, predicate); + + assertEquals(1, results.size()); + + Resource r = results.iterator().next(); + + Assert.assertEquals(ALERT_GROUP_NAME, + r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_NAME)); + + Assert.assertEquals(ALERT_GROUP_ID, + r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_ID)); + + Assert.assertEquals(ALERT_GROUP_CLUSTER_NAME, + r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME)); + + verify(amc, clusters, cluster, m_dao); + } + + /** + * @throws Exception + */ + @Test + public void testGetSingleResource() throws Exception { + Request request = PropertyHelper.getReadRequest( + AlertGroupResourceProvider.ALERT_GROUP_ID, + AlertGroupResourceProvider.ALERT_GROUP_NAME, + AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME, + AlertGroupResourceProvider.ALERT_GROUP_DEFAULT); + + AmbariManagementController amc = createMock(AmbariManagementController.class); + + Predicate predicate = new PredicateBuilder().property( + AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME).equals( + ALERT_GROUP_CLUSTER_NAME).and().property( + AlertGroupResourceProvider.ALERT_GROUP_ID).equals( + ALERT_GROUP_ID.toString()).toPredicate(); + + expect(m_dao.findGroupById(ALERT_GROUP_ID.longValue())).andReturn( + getMockEntities().get(0)); + + replay(amc, m_dao); + + AlertGroupResourceProvider provider = createProvider(amc); + Set<Resource> results = provider.getResources(request, predicate); + + assertEquals(1, results.size()); + + Resource r = results.iterator().next(); + + Assert.assertEquals(ALERT_GROUP_NAME, + r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_NAME)); + + Assert.assertEquals(ALERT_GROUP_ID, + r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_ID)); + + Assert.assertEquals(ALERT_GROUP_CLUSTER_NAME, + r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME)); + + verify(amc, m_dao); + } + + /** + * @throws Exception + */ + @Test + public void testCreateResources() throws Exception { + AmbariManagementController amc = createMock(AmbariManagementController.class); + Clusters clusters = createMock(Clusters.class); + Cluster cluster = createMock(Cluster.class); + expect(amc.getClusters()).andReturn(clusters).atLeastOnce(); + expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce(); + expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes(); + + Capture<List<AlertGroupEntity>> listCapture = new Capture<List<AlertGroupEntity>>(); + + m_dao.createGroups(capture(listCapture)); + expectLastCall(); + + replay(amc, clusters, cluster, m_dao); + + AlertGroupResourceProvider provider = createProvider(amc); + Map<String, Object> requestProps = new HashMap<String, Object>(); + requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_NAME, + ALERT_GROUP_NAME); + + requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME, + ALERT_GROUP_CLUSTER_NAME); + + Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null); + provider.createResources(request); + + Assert.assertTrue(listCapture.hasCaptured()); + AlertGroupEntity entity = listCapture.getValue().get(0); + Assert.assertNotNull(entity); + + Assert.assertEquals(ALERT_GROUP_NAME, entity.getGroupName()); + Assert.assertEquals(ALERT_GROUP_CLUSTER_ID, + entity.getClusterId().longValue()); + + verify(amc, clusters, cluster, m_dao); + } + + /** + * @throws Exception + */ + @Test + public void testUpdateResources() throws Exception { + } + + /** + * @throws Exception + */ + @Test + public void testDeleteResources() throws Exception { + AmbariManagementController amc = createMock(AmbariManagementController.class); + Clusters clusters = createMock(Clusters.class); + Cluster cluster = createMock(Cluster.class); + expect(amc.getClusters()).andReturn(clusters).atLeastOnce(); + expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce(); + expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes(); + + Capture<AlertGroupEntity> entityCapture = new Capture<AlertGroupEntity>(); + Capture<List<AlertGroupEntity>> listCapture = new Capture<List<AlertGroupEntity>>(); + + m_dao.createGroups(capture(listCapture)); + expectLastCall(); + + replay(amc, clusters, cluster, m_dao); + + AlertGroupResourceProvider provider = createProvider(amc); + + Map<String, Object> requestProps = new HashMap<String, Object>(); + requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_NAME, + ALERT_GROUP_NAME); + + requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME, + ALERT_GROUP_CLUSTER_NAME); + + Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null); + provider.createResources(request); + + Assert.assertTrue(listCapture.hasCaptured()); + AlertGroupEntity entity = listCapture.getValue().get(0); + Assert.assertNotNull(entity); + + Predicate predicate = new PredicateBuilder().property( + AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME).equals( + ALERT_GROUP_CLUSTER_NAME).and().property( + AlertGroupResourceProvider.ALERT_GROUP_ID).equals( + ALERT_GROUP_ID.toString()).toPredicate(); + + // everything is mocked, there is no DB + entity.setGroupId(ALERT_GROUP_ID); + + resetToStrict(m_dao); + expect(m_dao.findGroupById(ALERT_GROUP_ID.longValue())).andReturn(entity).anyTimes(); + m_dao.remove(capture(entityCapture)); + expectLastCall(); + replay(m_dao); + + provider.deleteResources(predicate); + + AlertGroupEntity entity1 = entityCapture.getValue(); + Assert.assertEquals(ALERT_GROUP_ID, entity1.getGroupId()); + + verify(amc, clusters, cluster, m_dao); + } + + /** + * @param amc + * @return + */ + private AlertGroupResourceProvider createProvider( + AmbariManagementController amc) { + return new AlertGroupResourceProvider( + PropertyHelper.getPropertyIds(Resource.Type.AlertGroup), + PropertyHelper.getKeyPropertyIds(Resource.Type.AlertGroup), amc); + } + + /** + * @return + */ + private List<AlertGroupEntity> getMockEntities() throws Exception { + AlertGroupEntity entity = new AlertGroupEntity(); + entity.setGroupId(ALERT_GROUP_ID); + entity.setGroupName(ALERT_GROUP_NAME); + entity.setClusterId(ALERT_GROUP_CLUSTER_ID); + entity.setDefault(false); + return Arrays.asList(entity); + } + + /** + * + */ + private class MockModule implements Module { + /** + * + */ + @Override + public void configure(Binder binder) { + binder.bind(AlertDispatchDAO.class).toInstance(m_dao); + binder.bind(Clusters.class).toInstance( + EasyMock.createNiceMock(Clusters.class)); + binder.bind(Cluster.class).toInstance( + EasyMock.createNiceMock(Cluster.class)); + binder.bind(ActionMetadata.class); + } + } +}