/*
* RHQ Management Platform
* Copyright (C) 2005-2008 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.enterprise.server.cloud;
import java.util.Arrays;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.authz.Permission;
import org.rhq.core.domain.cloud.AffinityGroup;
import org.rhq.core.domain.cloud.PartitionEventType;
import org.rhq.core.domain.cloud.Server;
import org.rhq.core.domain.cloud.composite.AffinityGroupCountComposite;
import org.rhq.core.domain.resource.Agent;
import org.rhq.core.domain.server.PersistenceUtility;
import org.rhq.core.domain.util.PageControl;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.server.RHQConstants;
import org.rhq.enterprise.server.authz.RequiredPermission;
import org.rhq.enterprise.server.authz.RequiredPermissions;
/**
* Manages CRUD operations for {@link AffinityGroup}s
*
* @author Joseph Marques
*/
@Stateless
public class AffinityGroupManagerBean implements AffinityGroupManagerLocal {
private final Log log = LogFactory.getLog(AffinityGroupManagerBean.class);
@PersistenceContext(unitName = RHQConstants.PERSISTENCE_UNIT_NAME)
private EntityManager entityManager;
@EJB
private PartitionEventManagerLocal partitionEventManager;
@RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
@RequiredPermission(Permission.MANAGE_INVENTORY) })
public AffinityGroup getById(Subject subject, int affinityGroupId) {
AffinityGroup affinityGroup = entityManager.find(AffinityGroup.class, affinityGroupId);
return affinityGroup;
}
@SuppressWarnings("unchecked")
@RequiredPermission(Permission.MANAGE_INVENTORY)
public PageList<Agent> getAgentMembers(Subject subject, int affinityGroupId, PageControl pageControl) {
pageControl.initDefaultOrderingField("a.name");
Query query = PersistenceUtility.createQueryWithOrderBy(entityManager, Agent.QUERY_FIND_BY_AFFINITY_GROUP,
pageControl);
Query countQuery = PersistenceUtility.createCountQuery(entityManager, Agent.QUERY_FIND_BY_AFFINITY_GROUP);
query.setParameter("affinityGroupId", affinityGroupId);
countQuery.setParameter("affinityGroupId", affinityGroupId);
long count = (Long) countQuery.getSingleResult();
List<Agent> results = query.getResultList();
return new PageList<Agent>(results, (int) count, pageControl);
}
@SuppressWarnings("unchecked")
@RequiredPermission(Permission.MANAGE_INVENTORY)
public PageList<Agent> getAgentNonMembers(Subject subject, int affinityGroupId, PageControl pageControl) {
pageControl.initDefaultOrderingField("a.name");
Query query = PersistenceUtility.createQueryWithOrderBy(entityManager, Agent.QUERY_FIND_WITHOUT_AFFINITY_GROUP,
pageControl);
Query countQuery = PersistenceUtility.createCountQuery(entityManager, Agent.QUERY_FIND_WITHOUT_AFFINITY_GROUP);
long count = (Long) countQuery.getSingleResult();
List<Agent> results = query.getResultList();
return new PageList<Agent>(results, (int) count, pageControl);
}
@SuppressWarnings("unchecked")
@RequiredPermission(Permission.MANAGE_INVENTORY)
public PageList<Server> getServerMembers(Subject subject, int affinityGroupId, PageControl pageControl) {
pageControl.initDefaultOrderingField("s.name");
Query query = PersistenceUtility.createQueryWithOrderBy(entityManager, Server.QUERY_FIND_BY_AFFINITY_GROUP,
pageControl);
Query countQuery = PersistenceUtility.createCountQuery(entityManager, Server.QUERY_FIND_BY_AFFINITY_GROUP);
query.setParameter("affinityGroupId", affinityGroupId);
countQuery.setParameter("affinityGroupId", affinityGroupId);
long count = (Long) countQuery.getSingleResult();
List<Server> results = query.getResultList();
return new PageList<Server>(results, (int) count, pageControl);
}
@SuppressWarnings("unchecked")
@RequiredPermission(Permission.MANAGE_INVENTORY)
public PageList<Server> getServerNonMembers(Subject subject, int affinityGroupId, PageControl pageControl) {
pageControl.initDefaultOrderingField("s.name");
Query query = PersistenceUtility.createQueryWithOrderBy(entityManager,
Server.QUERY_FIND_WITHOUT_AFFINITY_GROUP, pageControl);
Query countQuery = PersistenceUtility.createCountQuery(entityManager, Server.QUERY_FIND_WITHOUT_AFFINITY_GROUP);
long count = (Long) countQuery.getSingleResult();
List<Server> results = query.getResultList();
return new PageList<Server>(results, (int) count, pageControl);
}
@RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
@RequiredPermission(Permission.MANAGE_INVENTORY) })
public AffinityGroup update(Subject subject, AffinityGroup affinityGroup) throws AffinityGroupException {
validate(affinityGroup, true);
return entityManager.merge(affinityGroup);
}
@SuppressWarnings("unchecked")
@RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
@RequiredPermission(Permission.MANAGE_INVENTORY) })
public PageList<AffinityGroupCountComposite> getComposites(Subject subject, PageControl pageControl) {
pageControl.initDefaultOrderingField("ag.name");
Query query = PersistenceUtility.createQueryWithOrderBy(entityManager, AffinityGroup.QUERY_FIND_ALL_COMPOSITES,
pageControl);
int count = getAffinityGroupCount();
List<AffinityGroupCountComposite> results = query.getResultList();
return new PageList<AffinityGroupCountComposite>(results, count, pageControl);
}
public int getAffinityGroupCount() {
Query query = PersistenceUtility.createCountQuery(entityManager, AffinityGroup.QUERY_FIND_ALL);
try {
long serverCount = (Long) query.getSingleResult();
return (int) serverCount;
} catch (NoResultException nre) {
log.debug("Could not get AffinityGroup count, returning 0...");
return 0;
}
}
@RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
@RequiredPermission(Permission.MANAGE_INVENTORY) })
public int create(Subject subject, AffinityGroup affinityGroup) throws AffinityGroupException {
validate(affinityGroup, false);
entityManager.persist(affinityGroup);
return affinityGroup.getId();
}
private void validate(AffinityGroup affinityGroup, boolean alreadyExists) throws AffinityGroupException {
String name = (affinityGroup.getName() == null ? "" : affinityGroup.getName().trim());
if (name.equals("")) {
throw new AffinityGroupCreationException("Name is a required property");
}
if (name.length() > 100) {
throw new AffinityGroupCreationException("Name is limited to 100 characters");
}
Query query = entityManager.createNamedQuery(AffinityGroup.QUERY_FIND_BY_NAME);
query.setParameter("name", name.toUpperCase());
try {
AffinityGroup found = (AffinityGroup) query.getSingleResult();
if (alreadyExists == false) {
throw new AffinityGroupCreationException("AffinityGroup with name '" + name + "' already exists");
}
if (affinityGroup.getId() != found.getId()) {
throw new AffinityGroupUpdateException("AffinityGroup with name '" + name + "' already exists");
}
} catch (NoResultException e) {
// this is expected
}
}
@RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
@RequiredPermission(Permission.MANAGE_INVENTORY) })
public int delete(Subject subject, Integer[] affinityGroupIds) {
// A deleted affinity group forces a cloud repartitioning. Note, it is ok to request multiple
// cloud repartitions, they will be consolidated by the cloud manager job.
for (Integer agId : affinityGroupIds) {
AffinityGroup ag = entityManager.find(AffinityGroup.class, agId);
partitionEventManager.cloudPartitionEventRequest(subject, PartitionEventType.AFFINITY_GROUP_DELETE, ag
.getName());
}
Query updateAgentsQuery = entityManager.createNamedQuery(AffinityGroup.QUERY_UPDATE_REMOVE_AGENTS);
Query updateServersQuery = entityManager.createNamedQuery(AffinityGroup.QUERY_UPDATE_REMOVE_SERVERS);
Query removeQuery = entityManager.createNamedQuery(AffinityGroup.QUERY_DELETE_BY_IDS);
List<Integer> affinityGroups = Arrays.asList(affinityGroupIds);
updateAgentsQuery.setParameter("affinityGroupIds", affinityGroups);
updateServersQuery.setParameter("affinityGroupIds", affinityGroups);
removeQuery.setParameter("affinityGroupIds", affinityGroups);
int updatedAgents = updateAgentsQuery.executeUpdate();
int updatedServers = updateServersQuery.executeUpdate();
int removedAffinityGroups = removeQuery.executeUpdate();
log.debug("Removed " + removedAffinityGroups + " AffinityGroups: " + updatedAgents + " agents and "
+ updatedServers + " were updated");
return removedAffinityGroups;
}
@RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
@RequiredPermission(Permission.MANAGE_INVENTORY) })
public void addAgentsToGroup(Subject subject, int affinityGroupId, Integer[] agentIds) {
List<Integer> agentIdsList = Arrays.asList(agentIds);
AffinityGroup group = entityManager.find(AffinityGroup.class, affinityGroupId);
Query query = entityManager.createNamedQuery(AffinityGroup.QUERY_UPDATE_ADD_AGENTS);
query.setParameter("affinityGroup", group);
query.setParameter("agentIds", agentIdsList);
query.executeUpdate();
// Audit each changed affinity group assignment (is this too verbose?)
String auditString = group.getName() + " <-- ";
for (Integer agentId : agentIdsList) {
Agent agent = entityManager.find(Agent.class, agentId);
partitionEventManager.auditPartitionEvent(subject, PartitionEventType.AGENT_AFFINITY_GROUP_ASSIGN,
auditString + agent.getName());
}
// Now, request a cloud repartitioning due to the affinity group changes
partitionEventManager.cloudPartitionEventRequest(subject, PartitionEventType.AFFINITY_GROUP_CHANGE, group
.getName());
}
@RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
@RequiredPermission(Permission.MANAGE_INVENTORY) })
public void removeAgentsFromGroup(Subject subject, Integer[] agentIds) {
List<Integer> agentIdsList = Arrays.asList(agentIds);
Query query = entityManager.createNamedQuery(AffinityGroup.QUERY_UPDATE_REMOVE_SPECIFIC_AGENTS);
query.setParameter("agentIds", agentIdsList);
query.executeUpdate();
// Audit each changed affinity group assignment (is this too verbose?)
for (Integer agentId : agentIdsList) {
Agent agent = entityManager.find(Agent.class, agentId);
partitionEventManager.auditPartitionEvent(subject, PartitionEventType.AGENT_AFFINITY_GROUP_REMOVE, agent
.getName());
}
// Now, request a cloud repartitioning due to the affinity group changes
partitionEventManager.cloudPartitionEventRequest(subject, PartitionEventType.AFFINITY_GROUP_CHANGE,
PartitionEventType.AGENT_AFFINITY_GROUP_REMOVE.name());
}
@RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
@RequiredPermission(Permission.MANAGE_INVENTORY) })
public void addServersToGroup(Subject subject, int affinityGroupId, Integer[] serverIds) {
List<Integer> serverIdsList = Arrays.asList(serverIds);
AffinityGroup group = entityManager.find(AffinityGroup.class, affinityGroupId);
Query query = entityManager.createNamedQuery(AffinityGroup.QUERY_UPDATE_ADD_SERVERS);
query.setParameter("affinityGroup", group);
query.setParameter("serverIds", serverIdsList);
query.executeUpdate();
// Audit each changed affinity group assignment (is this too verbose?)
String auditString = group.getName() + " <-- ";
for (Integer serverId : serverIdsList) {
Server server = entityManager.find(Server.class, serverId);
partitionEventManager.auditPartitionEvent(subject, PartitionEventType.SERVER_AFFINITY_GROUP_ASSIGN,
auditString + server.getName());
}
// Now, request a cloud repartitioning due to the affinity group changes
partitionEventManager.cloudPartitionEventRequest(subject, PartitionEventType.AFFINITY_GROUP_CHANGE, group
.getName());
}
@RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
@RequiredPermission(Permission.MANAGE_INVENTORY) })
public void removeServersFromGroup(Subject subject, Integer[] serverIds) {
List<Integer> serverIdsList = Arrays.asList(serverIds);
Query query = entityManager.createNamedQuery(AffinityGroup.QUERY_UPDATE_REMOVE_SPECIFIC_SERVERS);
query.setParameter("serverIds", serverIdsList);
query.executeUpdate();
// Audit each changed affinity group assignment (is this too verbose?)
for (Integer serverId : serverIdsList) {
Server server = entityManager.find(Server.class, serverId);
partitionEventManager.auditPartitionEvent(subject, PartitionEventType.SERVER_AFFINITY_GROUP_REMOVE, server
.getName());
}
// Now, request a cloud repartitioning due to the affinity group changes
partitionEventManager.cloudPartitionEventRequest(subject, PartitionEventType.AFFINITY_GROUP_CHANGE,
PartitionEventType.AGENT_AFFINITY_GROUP_REMOVE.name());
}
}