Package com.abiquo.server.core.infrastructure

Source Code of com.abiquo.server.core.infrastructure.MachineDAO

/**
* Copyright (C) 2008 - Abiquo Holdings S.L. All rights reserved.
*
* Please see /opt/abiquo/tomcat/webapps/legal/ on Abiquo server
* or contact contact@abiquo.com for licensing information.
*/
package com.abiquo.server.core.infrastructure;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

import com.abiquo.model.enumerator.HypervisorType;
import com.abiquo.model.enumerator.MachineState;
import com.abiquo.server.core.cloud.Hypervisor;
import com.abiquo.server.core.cloud.VirtualMachineDAO;
import com.abiquo.server.core.common.persistence.DefaultDAOBase;
import com.abiquo.server.core.enterprise.Enterprise;
import com.abiquo.server.core.infrastructure.network.NetworkInterface;
import com.abiquo.server.core.infrastructure.network.NetworkServiceType;
import com.softwarementors.bzngine.entities.PersistentEntity;

@Repository("jpaMachineDAO")
@SuppressWarnings("unchecked")
public class MachineDAO extends DefaultDAOBase<Integer, Machine>
{

    public MachineDAO()
    {
        super(Machine.class);
    }

    public MachineDAO(final EntityManager entityManager)
    {
        super(Machine.class, entityManager);
    }

    private static Criterion sameDatacenter(final Datacenter datacenter)
    {
        assert datacenter != null;

        return Restrictions.eq(Machine.DATACENTER_PROPERTY, datacenter);
    }

    private static Criterion sameRack(final Rack rack)
    {
        assert rack != null;

        return Restrictions.eq(Machine.RACK_PROPERTY, rack);
    }

    private static Criterion sameId(final Integer id)
    {
        return Restrictions.eq(PersistentEntity.ID_PROPERTY, id);
    }

    private static Criterion sameName(final String name)
    {
        assert !StringUtils.isEmpty(name);

        return Restrictions.eq(Machine.NAME_PROPERTY, name);
    }

    private Criterion sameEnterprise(final Enterprise enterprise)
    {
        return Restrictions.eq(Machine.ENTERPRISE_PROPERTY, enterprise);
    }

    private Criterion sameEnterpriseOrNotReserved(final Enterprise enterprise)
    {
        return Restrictions.or(//
            Restrictions.isNull(Machine.ENTERPRISE_PROPERTY), //
            Restrictions.eq(Machine.ENTERPRISE_PROPERTY, enterprise));
    }

    private static Criterion sameState(final MachineState state)
    {
        return Restrictions.eq(Machine.STATE_PROPERTY, state);
    }

    private Criterion filterBy(final String filter)
    {
        Disjunction filterDisjunction = Restrictions.disjunction();

        filterDisjunction.add(Restrictions.like(Machine.NAME_PROPERTY, '%' + filter + '%'));

        return filterDisjunction;
    }

    public List<Machine> findMachines(final Datacenter datacenter)
    {
        Criteria criteria = createCriteria(sameDatacenter(datacenter));
        criteria.addOrder(Order.asc(Machine.NAME_PROPERTY));
        List<Machine> result = getResultList(criteria);
        return result;
    }

    public List<Machine> findRackMachines(final Rack rack)
    {
        return findRackMachines(rack, null);
    }

    public Integer numRackMachinesManaged(final Rack rack)
    {
        Criteria criteria = getSession().createCriteria(Machine.class);
        criteria.add(sameRack(rack));
        criteria.add(sameState(MachineState.MANAGED));

        return criteria.list().size();
    }

    public List<Machine> findRackMachines(final Rack rack, final String filter)
    {
        assert rack != null;
        assert isManaged2(rack);

        Criteria criteria = createCriteria(sameRack(rack));
        if (filter != null && !filter.isEmpty())
        {
            criteria.add(filterBy(filter));
        }
        criteria.addOrder(Order.asc(Machine.NAME_PROPERTY));
        List<Machine> result = getResultList(criteria);
        return result;
    }

    public List<Machine> findMachinesWithHAInProgress()
    {
        Criteria criteria = createCriteria(sameState(MachineState.HA_IN_PROGRESS));
        criteria.createAlias(Machine.HYPERVISOR_PROPERTY, "hypervisor");

        // Order by name
        criteria.addOrder(Order.asc(Machine.NAME_PROPERTY));

        return getResultList(criteria);
    }

    public List<Machine> findRackEnabledForHAMachines(final Rack rack)
    {
        if (rack instanceof UcsRack)
        {
            return findRackEnabledForHAMachinesInUcs((UcsRack) rack);
        }
        Criteria criteria = createCriteria(sameRack(rack));
        criteria.createAlias(Machine.HYPERVISOR_PROPERTY, "hypervisor");

        // Is a managed one
        criteria.add(Restrictions.in(Machine.STATE_PROPERTY, new Object[] {MachineState.MANAGED,
        MachineState.STOPPED, MachineState.PROVISIONED}));

        // Has fencing capabilities
        criteria.add(Restrictions.isNotNull(Machine.IPMI_IP_PROPERTY));
        criteria.add(Restrictions.isNotNull(Machine.IPMI_USER_PROPERTY));
        criteria.add(Restrictions.isNotNull(Machine.IPMI_PASSWORD_PROPERTY));

        // XenServer does not support HA
        criteria.add(Restrictions.ne("hypervisor." + Hypervisor.TYPE_PROPERTY,
            HypervisorType.XENSERVER));

        // Order by name
        criteria.addOrder(Order.asc(Machine.NAME_PROPERTY));

        return getResultList(criteria);
    }

    public List<Machine> findRackEnabledForHAMachinesInUcs(final UcsRack rack)
    {
        Criteria criteria = createCriteria(sameRack(rack));
        criteria.createAlias(Machine.HYPERVISOR_PROPERTY, "hypervisor");

        // Is a managed one
        criteria.add(Restrictions.eq(Machine.STATE_PROPERTY, MachineState.MANAGED));

        // XenServer does not support HA
        criteria.add(Restrictions.ne("hypervisor." + Hypervisor.TYPE_PROPERTY,
            HypervisorType.XENSERVER));

        // Order by name
        criteria.addOrder(Order.asc(Machine.NAME_PROPERTY));

        return getResultList(criteria);
    }

    public boolean existsAnyWithDatacenterAndName(final Datacenter datacenter, final String name)
    {
        assert datacenter != null;
        assert !StringUtils.isEmpty(name);

        return existsAnyByCriterions(sameDatacenter(datacenter), sameName(name));
    }

    public boolean existsAnyOtherWithDatacenterAndName(final Machine machine, final String name)
    {
        assert machine != null;
        assert !StringUtils.isEmpty(name);

        return existsAnyOtherByCriterions(machine, sameDatacenter(machine.getDatacenter()),
            sameName(name));
    }

    public int deleteRackMachines(final Rack rack)
    {
        assert rack != null;
        assert isManaged2(rack);

        Collection<Machine> machines = findRackMachines(rack);
        for (Machine machine : machines)
        {
            remove(machine);
        }
        return machines.size();
    }

    // public List<Machine> findCandidateMachines(final Integer idRack,
    // final Integer idVirtualDatacenter,
    // final Enterprise enterprise, final VirtualMachineRequirements vmReq){
    //
    // return findCandidateMachines(idRack,idVirtualDatacenter, vmReq.getHd(), enterprise,
    // vmReq.getNsts());
    // }
    //

    /**
     * Count the number of MANAGED Machines in some rack of the Datacenter for the specified
     * HypervisorType. Take into account if the Enterprise have some (exclusive) restrictions.
     * <p>
     * To use in the anti-affinity (first vm in the vapp, so rack in not already selected) check is
     * can hold more than {@link VirtualMachineDAO#numInLayer(Integer, String)}
     */
    public Long numPossibleAvailableMachines(final Enterprise enterprise,
        final Datacenter datacenter, final HypervisorType hypervisorType)
    {
        return numPossibleAvailableMachines(enterprise, null, datacenter, hypervisorType,
            Collections.EMPTY_LIST);
    }

    /**
     * Count the number of MANAGED Machines in the Datacenter for the specified HypervisorType. Take
     * into account if the Enterprise have some (exclusive) restrictions.
     * <p>
     * To use in the anti-affinity (some vm in the vapp already restrict the rack) check is can hold
     * more than {@link VirtualMachineDAO#numInLayer(Integer, String)}
     *
     * @param bannedMachineIds, already used machine in other virtual machines with the same layer
     */
    public Long numPossibleAvailableMachines(final Enterprise enterprise, final Rack rack,
        final HypervisorType hypervisorType, final List<Integer> bannedMachineIds)
    {
        return numPossibleAvailableMachines(enterprise, rack, null, hypervisorType,
            bannedMachineIds);
    }

    private final String COUNT_PROJ_NAME = "numMachines";

    /** The rack or the datacenter provided */
    private Long numPossibleAvailableMachines(final Enterprise enterprise, final Rack rack,
        final Datacenter datacenter, final HypervisorType hypervisorType,
        final List<Integer> bannedMachineIds)
    {
        Criteria criteria = getSession().createCriteria(Machine.class);
        criteria.createAlias(Machine.HYPERVISOR_PROPERTY, "hypervisor");

        if (!CollectionUtils.isEmpty(bannedMachineIds))
        {
            criteria.add(Restrictions.not(Restrictions.in(PersistentEntity.ID_PROPERTY,
                bannedMachineIds)));
        }

        if (enterprise.getIsReservationRestricted())
        {
            criteria.add(sameEnterprise(enterprise));
        }
        else
        {
            criteria.add(sameEnterpriseOrNotReserved(enterprise));
        }

        // same hypervisor type
        criteria.add(Restrictions.eq("hypervisor." + Hypervisor.TYPE_PROPERTY, hypervisorType));

        if (rack != null)
        {
            criteria.add(sameRack(rack));

            criteria.setProjection(Projections.count(PersistentEntity.ID_PROPERTY).as(
                COUNT_PROJ_NAME));
            criteria.addOrder(Order.asc(COUNT_PROJ_NAME));

        }
        else if (datacenter != null)
        {
            criteria.add(sameDatacenter(datacenter));

            criteria.createAlias(Machine.RACK_PROPERTY, "rack");
            criteria.setProjection(Projections.projectionList()//
                .add(Projections.groupProperty("rack." + PersistentEntity.ID_PROPERTY))//
                .add(Projections.count(PersistentEntity.ID_PROPERTY).as(COUNT_PROJ_NAME)));

            criteria.addOrder(Order.desc(COUNT_PROJ_NAME));
        }

        criteria.add(sameState(MachineState.MANAGED));

        List<Object> list = criteria.list();

        if (CollectionUtils.isEmpty(list))
        {
            return 0l;
        }
        else
        {
            if (rack != null) // don't use projections
            {
                return (Long) list.get(0);
            }
            else
            {
                // use rackId projection
                Object[] idRackAndCount = (Object[]) list.get(0);
                return (Long) idRackAndCount[1];
            }
        }
    }

    public List<Machine> findCandidateMachines(final Integer idRack,
        final Integer idVirtualDatacenter, final Enterprise enterprise,
        final Integer originalHypervisorId, final String datastoreUuid,
        final List<NetworkServiceType> nsts)
    {
        return findCandidateMachines(idRack, idVirtualDatacenter, enterprise, originalHypervisorId,
            datastoreUuid, nsts, null, null);
    }

    public List<Machine> findCandidateMachines(final Integer idRack,
        final Integer idVirtualDatacenter, final Long hdRequiredOnDatastore,
        final Enterprise enterprise, final List<NetworkServiceType> nsts)
    {
        return findCandidateMachines(idRack, idVirtualDatacenter, hdRequiredOnDatastore,
            enterprise, nsts, null, null);
    }

    public List<Machine> findCandidateMachines(final Integer idRack,
        final Integer idVirtualDatacenter, final Long hdRequiredOnDatastore,
        final Enterprise enterprise, final List<NetworkServiceType> nsts, final String layerName,
        final Integer idVirtualAppliance)
    {

        List<Machine> machines;

        if (enterprise.getIsReservationRestricted())
        {
            machines =
                findFirstCandidateMachinesReservedRestricted(idRack, idVirtualDatacenter,
                    hdRequiredOnDatastore, enterprise);
        }
        else
        {
            machines =
                findFirstCandidateMachines(idRack, idVirtualDatacenter, hdRequiredOnDatastore,
                    enterprise);
        }

        // StringBuilder sbcandidates = new StringBuilder();
        List<Integer> candidatesids = new LinkedList<Integer>();
        for (Machine m : machines)
        {
            candidatesids.add(m.getId());
        }

        // with datastore
        Query datastoreQuery = getSession().createQuery(QUERY_CANDIDATE_DATASTORE);
        datastoreQuery.setLong("hdRequiredOnRepository", hdRequiredOnDatastore);
        datastoreQuery.setParameterList("candidates", candidatesids);

        List<Integer> includedIds = datastoreQuery.list();

        if (includedIds.size() == 0)
        {
            throw new PersistenceException(String.format(
                "There are no machines with the required datastore capacity [%d]",
                hdRequiredOnDatastore));
        }

        // execute the enterprise exclusion rule
        Query excludedQuery = getSession().createQuery(QUERY_CANDIDATE_NO_ENTERPRISE_EXCLUDED);
        excludedQuery.setParameter("enterpriseId", enterprise.getId());
        List<Integer> excludedMachineIds = excludedQuery.list();

        List<Machine> notExcludedMachines = new LinkedList<Machine>();

        for (Machine m : machines)
        {
            Integer machineId = m.getId();

            if (!excludedMachineIds.contains(machineId) && includedIds.contains(machineId))
            {
                notExcludedMachines.add(m);
            }
        }

        if (notExcludedMachines.size() == 0)
        {
            throw new PersistenceException("All the candidate machines are excluded by other enterprises "
                + "with virtual machines deployed on it. Please check the enterprise affinity rules.");
        }

        // Apply the network service types filters.
        // The machines should have all the network service types so can be deployed
        List<Machine> allNSTsMachines = new LinkedList<Machine>();
        for (Machine candidateMachine : notExcludedMachines)
        {
            // Build a List of all the network service types of the machine
            List<NetworkServiceType> machineNSTs = new ArrayList<NetworkServiceType>();
            for (NetworkInterface ni : candidateMachine.getNetworkInterfaces())
            {
                machineNSTs.add(ni.getNetworkServiceType());
            }

            // Now, all the needed 'nsts' should belong to the list of 'machineNSTs'
            Boolean allInto = true;
            for (NetworkServiceType nst : nsts)
            {
                if (!machineNSTs.contains(nst))
                {
                    allInto = false;
                    break;
                }
            }

            if (allInto)
            {
                // all the nsts found. Put it into the allNSTsMachines
                allNSTsMachines.add(candidateMachine);
            }
        }

        if (allNSTsMachines.size() == 0)
        {
            throw new PersistenceException("No candidate machine is capable of handling the Network Service Type's requirements:"
                + " could not deploy the Virtual Machine and attach its NICs properly");
        }

        // Excluding by Layer if Affinity rules apply
        if (layerName != null)
        {
            Query layerQuery = getSession().createQuery(QUERY_EXCLUDED_CANDIDATE_BY_LAYER);
            layerQuery.setParameter("layer_name", layerName);
            layerQuery.setParameter("vapp_id", idVirtualAppliance);
            List<Integer> layerExcludedMachineIds = layerQuery.list();
            List<Machine> notExcludedMachinesByLayer = new LinkedList<Machine>();

            for (Machine m : allNSTsMachines)
            {
                Integer machineId = m.getId();

                if (!layerExcludedMachineIds.contains(machineId))
                {
                    notExcludedMachinesByLayer.add(m);
                }
            }

            if (notExcludedMachinesByLayer.size() == 0)
            {
                throw new PersistenceException("All the candidate machines are excluded by other machines "
                    + "with virtual machines deployed on it in the same layer.");
            }

            return notExcludedMachinesByLayer;

        }

        return allNSTsMachines;
    }

    private List<Machine> findFirstCandidateMachines(final Integer idRack,
        final Integer idVirtualDatacenter, final Long hdRequiredOnDatastore,
        final Enterprise enterprise)
    {
        List<Machine> machines = null;

        Query query = getSession().createQuery(QUERY_CANDIDATE_MACHINES);

        query.setInteger("idVirtualDataCenter", idVirtualDatacenter);
        query.setInteger("idRack", idRack);
        query.setParameter("state", MachineState.MANAGED);
        query.setParameter("enterpriseId", enterprise.getId());

        machines = query.list();

        if (machines == null || machines.size() == 0)
        {
            whyNotCandidateMachines(idRack, idVirtualDatacenter, hdRequiredOnDatastore, enterprise,
                null);
        }

        return machines;
    }

    private List<Machine> findFirstCandidateMachinesReservedRestricted(final Integer idRack,
        final Integer idVirtualDatacenter, final Long hdRequiredOnDatastore,
        final Enterprise enterprise)
    {

        List<Machine> machines = null;

        List<Machine> reservMachines = findReservedMachines(enterprise);

        if (reservMachines != null && reservMachines.size() != 0)
        {
            List<Integer> reserveds = new LinkedList<Integer>();
            for (Machine m : reservMachines)
            {
                reserveds.add(m.getId());
            }

            Query query = getSession().createQuery(QUERY_CANDIDATE_MACHINES_RESERVED);
            query.setInteger("idVirtualDataCenter", idVirtualDatacenter);
            query.setInteger("idRack", idRack);
            query.setParameter("state", MachineState.MANAGED);
            query.setParameterList("reserveds", reserveds);

            machines = query.list();

            if (machines == null || machines.size() == 0)
            {
                whyNotCandidateMachines(idRack, idVirtualDatacenter, hdRequiredOnDatastore,
                    enterprise, reserveds);
            }

            return machines;
        }
        else
        {
            final String msg =
                String
                    .format(
                        "Enterprise works in restricted reserved machines mode but no machine is reserved. Current enterprise: %s",
                        enterprise.getName());

            throw new PersistenceException(msg);
        }
    }

    protected List<Machine> findFirstCandidateMachinesReservedRestrictedHAExclude(
        final Integer idRack, final Integer idVirtualDatacenter, final Enterprise enterprise,
        final Integer originalHypervisorId)
    {

        List<Machine> machines = null;

        List<Machine> reservMachines = findReservedMachines(enterprise);

        if (reservMachines != null && reservMachines.size() != 0)
        {
            List<Integer> reserveds = new LinkedList<Integer>();
            for (Machine m : reservMachines)
            {
                reserveds.add(m.getId());
            }

            Query query =
                getSession().createQuery(QUERY_CANDIDATE_MACHINES_RESERVED_HA_EXCLUDE_ORIGINAL);
            query.setInteger("idVirtualDataCenter", idVirtualDatacenter);
            query.setInteger("idRack", idRack);
            query.setParameter("state", MachineState.MANAGED);
            query.setParameterList("reserveds", reserveds);
            query.setInteger("enterpriseId", enterprise.getId());
            query.setInteger("originalHypervisorId", originalHypervisorId);

            machines = query.list();

            if (machines == null || machines.size() == 0)
            {
                whyNotCandidateMachines(idRack, idVirtualDatacenter, 0l, enterprise, reserveds);
            }

            return machines;
        }
        else
        {
            final String msg =
                String
                    .format(
                        "Enterprise works in restricted reserved machines mode but no machine is reserved. Current enterprise: %s",
                        enterprise.getName());

            throw new PersistenceException(msg);
        }

    }

    /**
     * Do not require additional space on the datastore. Used during HA, selects a machine different
     * of the ''originalHypervisorId'' with the same ''datastoreUuid'' enabled.
     */
    public List<Machine> findCandidateMachines(final Integer idRack,
        final Integer idVirtualDatacenter, final Enterprise enterprise,
        final Integer originalHypervisorId, final String datastoreUuid,
        final List<NetworkServiceType> nsts, final String layerName,
        final Integer idVirtualAppliance)
    {

        List<Machine> machines = null;
        if (enterprise.getIsReservationRestricted())
        {
            machines =
                findFirstCandidateMachinesReservedRestrictedHAExclude(idRack, idVirtualDatacenter,
                    enterprise, originalHypervisorId);
        }

        else
        {
            Query query = getSession().createQuery(QUERY_CANDIDATE_MACHINES_HA_EXCLUDE_ORIGINAL);
            query.setInteger("idVirtualDataCenter", idVirtualDatacenter);
            query.setInteger("idRack", idRack);
            query.setParameter("state", MachineState.MANAGED);
            query.setParameter("enterpriseId", enterprise.getId());
            query.setParameter("originalHypervisorId", originalHypervisorId);

            machines = query.list();
        }

        if (machines == null || machines.size() == 0)
        {
            Query query = getSession().createQuery(QUERY_CANDIDATE_MACHINES);
            query.setInteger("idVirtualDataCenter", idVirtualDatacenter);
            query.setInteger("idRack", idRack);
            query.setParameter("state", MachineState.MANAGED);
            query.setParameter("enterpriseId", enterprise.getId());

            machines = query.list();

            if (machines == null || machines.size() == 0)
            {
                throw new PersistenceException(String.format(
                    "Could not find a MANAGED machine on rack [%d] and in virtual datacenter [%d] available for the current enterprise [%s]. "
                        + "Please check the machine reservation policies.", idRack,
                    idVirtualDatacenter, enterprise.getName()));
            }
            else
            {
                throw new PersistenceException(String.format(
                    "The only MANAGED machine on the required rack [%d] and virtual datacenter [%d] available for the current enterprise [%s] "
                        + "is the target of the high availability (so can't be used) ", idRack,
                    idVirtualDatacenter, enterprise.getName()));
            }
        }

        // StringBuilder sbcandidates = new StringBuilder();
        List<Integer> candidatesids = new LinkedList<Integer>();
        for (Machine m : machines)
        {
            candidatesids.add(m.getId());
        }

        // with datastore
        Query datastoreQuery = getSession().createQuery(QUERY_CANDIDATE_DATASTORE_HA_DATASTOREUUID);
        datastoreQuery.setParameterList("candidates", candidatesids);
        datastoreQuery.setParameter("datastoreUuid", datastoreUuid);

        List<Integer> includedIds = datastoreQuery.list();

        if (includedIds.size() == 0)
        {
            throw new PersistenceException(String.format(
                "There is no machine with the required shared datastore [%s]", datastoreUuid));
        }

        // execute the enterprise exclusion rule
        Query excludedQuery = getSession().createQuery(QUERY_CANDIDATE_NO_ENTERPRISE_EXCLUDED);
        excludedQuery.setParameter("enterpriseId", enterprise.getId());
        List<Integer> excludedMachineIds = excludedQuery.list();

        List<Machine> notExcludedMachines = new LinkedList<Machine>();

        for (Machine m : machines)
        {
            Integer machineId = m.getId();

            if (!excludedMachineIds.contains(machineId) && includedIds.contains(machineId))
            {
                notExcludedMachines.add(m);
            }
        }

        if (notExcludedMachines.size() == 0)
        {
            throw new PersistenceException("All the candidate machines are excluded by other enterprises "
                + "with virtual machines deployed on it. Please check the enterprise affinity rules.");
        }

        // Apply the network service types filters.
        // The machines should have all the network service types so can be deployed
        List<Machine> allNSTsMachines = new LinkedList<Machine>();
        for (Machine candidateMachine : notExcludedMachines)
        {
            // Build a List of all the network service types of the machine
            List<NetworkServiceType> machineNSTs = new ArrayList<NetworkServiceType>();
            for (NetworkInterface ni : candidateMachine.getNetworkInterfaces())
            {
                machineNSTs.add(ni.getNetworkServiceType());
            }

            // Now, all the needed 'nsts' should belong to the list of 'machineNSTs'
            Boolean allInto = true;
            for (NetworkServiceType nst : nsts)
            {
                if (!machineNSTs.contains(nst))
                {
                    allInto = false;
                    break;
                }
            }

            if (allInto)
            {
                // all the nsts found. Put it into the allNSTsMachines
                allNSTsMachines.add(candidateMachine);
            }
        }

        if (allNSTsMachines == null || allNSTsMachines.size() == 0)
        {
            throw new PersistenceException(String.format(
                "All of the candidate machines in rack [%d] were excluded because Network Service Types required didn't match. Please check your Network Interfaces configurations.",
                idRack));
        }

        // Excluding by Layer if Affinity rules apply
        if (layerName != null)
        {
            Query layerQuery = getSession().createQuery(QUERY_EXCLUDED_CANDIDATE_BY_LAYER);
            layerQuery.setParameter("layer_name", layerName);
            layerQuery.setParameter("vapp_id", idVirtualAppliance);
            List<Integer> layerExcludedMachineIds = layerQuery.list();
            List<Machine> notExcludedMachinesByLayer = new LinkedList<Machine>();

            for (Machine m : allNSTsMachines)
            {
                Integer machineId = m.getId();

                if (!layerExcludedMachineIds.contains(machineId))
                {
                    notExcludedMachinesByLayer.add(m);
                }
            }

            if (notExcludedMachinesByLayer.size() == 0)
            {
                throw new PersistenceException("All the candidate machines are excluded by other machines "
                    + "with virtual machines deployed on it in the same layer.");
            }

            return notExcludedMachinesByLayer;

        }

        return allNSTsMachines;
    }

    private void whyNotCandidateMachines(final Integer idRack, final Integer idVirtualDatacenter,
        final Long hdRequiredOnDatastore, final Enterprise enterprise, final List<Integer> reserveds)
        throws PersistenceException
    {

        if (reserveds != null)
        {

            StringBuilder reservedMachinesB =
                new StringBuilder(String.format(
                    "Enterprise %s has the following machine reservations : ", enterprise.getName()));
            for (Integer mid : reserveds)
            {
                reservedMachinesB.append(String.valueOf(mid) + " ");
            }

            /**
             * rack and hypervisor type
             */
            Query query1 =
                getSession().createQuery(WHY_QUERY_CANDIDATE_SAME_VDC_RACK_AND_TYPE_AND_RESERVED);
            query1.setInteger("idVirtualDataCenter", idVirtualDatacenter);
            query1.setInteger("idRack", idRack);
            query1.setParameterList("reserveds", reserveds);

            List<Integer> query1res = query1.list();

            if (query1res.size() == 0)
            {
                throw new PersistenceException(String.format(
                    "%s\nThere is no machine on the required rack [%d] and virtual datacenter [%d]. "
                        + "Please check the racks and hypervisor technology on the infrastructure.",
                    reservedMachinesB.toString(), idRack, idVirtualDatacenter));
            }

            /**
             * rack, hypervisor type and managed state
             */
            Query query2 = getSession().createQuery(QUERY_CANDIDATE_MACHINES_RESERVED);
            query2.setInteger("idVirtualDataCenter", idVirtualDatacenter);
            query2.setInteger("idRack", idRack);
            query2.setParameter("state", MachineState.MANAGED);
            query2.setParameterList("reserveds", reserveds);

            List<Integer> query2res = query2.list();

            if (query2res.size() == 0)
            {
                throw new PersistenceException(String.format(
                    "%s\nCould not find a MANAGED machine on rack [%d] and in virtual datacenter [%d]. "
                        + "Please check the machine health on the infrastructure.",
                    reservedMachinesB.toString(), idRack, idVirtualDatacenter));
            }

            /**
             * rack, hypervisor type, managed state, enterprise reservation and datastore capacity.
             */
            throw new PersistenceException(String.format(
                "%s\nThere is no machine with the required datastore capacity [%d]",
                reservedMachinesB.toString(), hdRequiredOnDatastore));
        } // reserved machines
        else
        {
            /**
             * rack and hypervisor type
             */
            Query query1 = getSession().createQuery(WHY_QUERY_CANDIDATE_SAME_VDC_RACK_AND_TYPE);
            query1.setInteger("idVirtualDataCenter", idVirtualDatacenter);
            query1.setInteger("idRack", idRack);

            List<Integer> query1res = query1.list();

            if (query1res.size() == 0)
            {
                throw new PersistenceException(String.format(
                    "There is no machine on the required rack [%d] and virtual datacenter [%d]. "
                        + "Please check the racks and hypervisor technology on the infrastructure.",
                    idRack, idVirtualDatacenter));
            }

            /**
             * rack, hypervisor type and managed state
             */
            Query query2 =
                getSession().createQuery(WHT_QUERY_CANDIDATE_SAME_VDC_RACK_AND_TYPE_AND_STATE);
            query2.setInteger("idVirtualDataCenter", idVirtualDatacenter);
            query2.setInteger("idRack", idRack);
            query2.setParameter("state", MachineState.MANAGED);

            List<Integer> query2res = query2.list();

            if (query2res.size() == 0)
            {
                throw new PersistenceException(String.format(
                    "Could not find a MANAGED machine on rack [%d] and in virtual datacenter [%d]. "
                        + "Please check the machine health on the infrastructure.", idRack,
                    idVirtualDatacenter));
            }

            /**
             * rack, hypervisor type, managed state and enterprise reservation
             */
            Query query3 = getSession().createQuery(QUERY_CANDIDATE_MACHINES);
            query3.setInteger("idVirtualDataCenter", idVirtualDatacenter);
            query3.setInteger("idRack", idRack);
            query3.setParameter("state", MachineState.MANAGED);
            query3.setParameter("enterpriseId", enterprise.getId());

            List<Integer> query3res = query3.list();

            if (query3res.size() == 0)
            {
                throw new PersistenceException(String.format(
                    "Could not find a MANAGED machine on rack [%d] and in virtual datacenter [%d] available for the current enterprise [%s]. "
                        + "Pleas check the machine reservation policies.", idRack,
                    idVirtualDatacenter, enterprise.getName()));
            }

            /**
             * rack, hypervisor type, managed state, enterprise reservation and datastore capacity.
             */
            throw new PersistenceException(String.format(
                "There is no machine with the required datastore capacity [%d]",
                hdRequiredOnDatastore));
        }
    }

    public List<Machine> findReservedMachines(final Enterprise enterprise)
    {
        Criteria criteria = createCriteria(sameEnterprise(enterprise));
        criteria.addOrder(Order.asc(Machine.NAME_PROPERTY));
        List<Machine> result = getResultList(criteria);
        return result;
    }

    public Machine findReservedMachine(final Enterprise enterprise, final Integer machineId)
    {
        Criteria criteria = createCriteria(sameEnterprise(enterprise), sameId(machineId));
        return (Machine) criteria.uniqueResult();
    }

    public void reserveMachine(final Machine machine, final Enterprise enterprise)
    {
        machine.setEnterprise(enterprise);
        flush();
    }

    public void releaseMachine(final Machine machine)
    {
        machine.setEnterprise(null);
        flush();
    }

    // idVirtualDataCenter, idRack
    private final static String WHY_QUERY_CANDIDATE_SAME_VDC_RACK_AND_TYPE = //
        "SELECT m.id FROM " + //
            "com.abiquo.server.core.infrastructure.Machine m, " + //
            "com.abiquo.server.core.cloud.VirtualDatacenter vdc " + //
            "WHERE " + //
            "vdc.id = :idVirtualDataCenter " + //
            "AND m.hypervisor.type = vdc.hypervisorType " + //
            "AND m.rack.id = :idRack " + //
            "AND m.enterprise is null";

    // idVirtualDataCenter, idRack, state
    private final static String WHT_QUERY_CANDIDATE_SAME_VDC_RACK_AND_TYPE_AND_STATE = //
        "SELECT m.id FROM " + //
            "com.abiquo.server.core.infrastructure.Machine m, " + //
            "com.abiquo.server.core.cloud.VirtualDatacenter vdc " + //
            "WHERE " + //
            "vdc.id = :idVirtualDataCenter " + //
            "AND m.hypervisor.type = vdc.hypervisorType " + //
            "AND m.rack.id = :idRack " + //
            "AND m.state = :state " + //
            "AND m.enterprise is null";

    // reserved, idVirtualDataCenter, idRack
    private final static String WHY_QUERY_CANDIDATE_SAME_VDC_RACK_AND_TYPE_AND_RESERVED = //
        "SELECT m.id FROM " + //
            "com.abiquo.server.core.infrastructure.Machine m, " + //
            "com.abiquo.server.core.cloud.VirtualDatacenter vdc " + //
            "WHERE m.id in (:reserveds) AND " + //
            "vdc.id = :idVirtualDataCenter " + //
            "AND m.hypervisor.type = vdc.hypervisorType " + //
            "AND m.rack.id = :idRack ";

    private final static String QUERY_CANDIDATE_NO_ENTERPRISE_EXCLUDED = //
        "SELECT vm.hypervisor.machine.id "
            + //
            "FROM com.abiquo.server.core.cloud.VirtualMachine vm WHERE "
            + //
            "   (vm.enterprise.id IN "
            + "      ( SELECT rule.enterprise2.id FROM com.abiquo.server.core.scheduler.EnterpriseExclusionRule rule WHERE rule.enterprise1.id = :enterpriseId ))"
            + " OR "
            + "   (vm.enterprise.id IN "
            + "      ( SELECT rule.enterprise1.id FROM com.abiquo.server.core.scheduler.EnterpriseExclusionRule rule WHERE rule.enterprise2.id = :enterpriseId ))"
            + " group by vm.hypervisor.machine.id";

    // idVirtualDataCenter, idRack, state, enterprise
    private final static String QUERY_CANDIDATE_MACHINES = //
        "SELECT m FROM " + //
            "com.abiquo.server.core.infrastructure.Machine m, " + //
            "com.abiquo.server.core.cloud.VirtualDatacenter vdc " + //
            "WHERE " + //
            "vdc.id = :idVirtualDataCenter " + //
            "AND m.hypervisor.type = vdc.hypervisorType " + //
            "AND m.rack.id = :idRack " + //
            "AND m.state = :state " + //
            "AND (m.enterprise is null OR m.enterprise.id = :enterpriseId) ";

    /**
     * HA related
     */

    // idVirtualDataCenter, idRack, state, enterprise, originalHypervisorId
    private final static String QUERY_CANDIDATE_MACHINES_HA_EXCLUDE_ORIGINAL = //
        "SELECT m FROM " + //
            "com.abiquo.server.core.infrastructure.Machine m, " + //
            "com.abiquo.server.core.cloud.VirtualDatacenter vdc " + //
            "WHERE " + //
            "vdc.id = :idVirtualDataCenter " + //
            "AND m.hypervisor.type = vdc.hypervisorType " + //
            "AND m.rack.id = :idRack " + //
            "AND m.state = :state " + //
            "AND (m.enterprise is null OR m.enterprise.id = :enterpriseId) " + //
            "AND m.hypervisor.id <> :originalHypervisorId";

    // reserved, idVirtualDataCenter, idRack, state
    private final static String QUERY_CANDIDATE_MACHINES_RESERVED = //
        "SELECT m FROM " + //
            "com.abiquo.server.core.infrastructure.Machine m, " + //
            "com.abiquo.server.core.cloud.VirtualDatacenter vdc " + //
            "WHERE m.id in (:reserveds) AND " + //
            "vdc.id = :idVirtualDataCenter " + //
            "AND m.hypervisor.type = vdc.hypervisorType " + //
            "AND m.rack.id = :idRack " + //
            "AND m.state = :state ";

    // reserved, idVirtualDataCenter, idRack, state, enterprise, orignalHypervisorId
    private final static String QUERY_CANDIDATE_MACHINES_RESERVED_HA_EXCLUDE_ORIGINAL = //
        "SELECT m FROM " + //
            "com.abiquo.server.core.infrastructure.Machine m, " + //
            "com.abiquo.server.core.cloud.VirtualDatacenter vdc " + //
            "WHERE m.id in (:reserveds) AND " + //
            "vdc.id = :idVirtualDataCenter " + //
            "AND m.hypervisor.type = vdc.hypervisorType " + //
            "AND m.rack.id = :idRack " + //
            "AND m.state = :state " + //
            "AND (m.enterprise is null OR m.enterprise.id = :enterpriseId) " + //
            "AND m.hypervisor.id <> :originalHypervisorId";

    private final static String QUERY_CANDIDATE_DATASTORE = //
        "  SELECT resources.machine.id FROM " + //
            "  com.abiquo.server.core.infrastructure.Datastore datastore, " + //
            "  com.abiquo.server.core.infrastructure.ScheduledResources resources " + //
            "    WHERE resources.machine.id in (:candidates)" + //
            "    AND (datastore.size - resources.datastoreUsed) > :hdRequiredOnRepository " + //
            "    AND datastore.id = resources.datastore.id " + //
            "    AND datastore.size > resources.datastoreUsed " + //
            "    AND datastore.enabled = true";

    private final static String QUERY_CANDIDATE_DATASTORE_HA_DATASTOREUUID = //
        "  SELECT resources.machine.id FROM " + //
            "  com.abiquo.server.core.infrastructure.Datastore datastore, " + //
            "  com.abiquo.server.core.infrastructure.ScheduledResources resources " + //
            "    WHERE resources.machine.id in (:candidates)" + //
            "    AND datastore.id = resources.datastore.id" + //
            "    AND datastore.size > resources.datastoreUsed " + //
            "    AND datastore.enabled = true " + //
            "    AND datastore.datastoreUUID = :datastoreUuid";

    // Selects Machines with VirtualMachines deployed in the same layer. They will be excluded
    public static final String QUERY_EXCLUDED_CANDIDATE_BY_LAYER = //
        " SELECT DISTINCT hy.machine.id FROM " + //
            "   com.abiquo.server.core.cloud.VirtualMachine vm, " + //
            "   com.abiquo.server.core.cloud.Hypervisor hy, " + //
            "   com.abiquo.server.core.cloud.NodeVirtualImage nvi " + //
            "       WHERE vm.hypervisor.id = hy.id " + //
            "       AND nvi.virtualMachine.id = vm.id " + //
            "       AND nvi.virtualAppliance.id = :vapp_id " + //
            "       AND vm.layer = :layer_name";

    public Machine findByIds(final Integer datacenterId, final Integer rackId,
        final Integer machineId)
    {
        return findUniqueByCriterions(Restrictions.eq("datacenter.id", datacenterId),
            Restrictions.eq("rack.id", rackId), Restrictions.eq("id", machineId));
    }

    public Machine findByIp(final Datacenter datacenter, final String ip)
    {
        Criteria crit = createCriteria();
        crit.createAlias(Machine.HYPERVISOR_PROPERTY, "hypervisor");

        crit.add(sameDatacenter(datacenter));
        crit.add(Restrictions.eq("hypervisor.ip", ip));

        return (Machine) crit.uniqueResult();
    }

    public Set<Integer> findAllIds()
    {
        Set<Integer> ids = new HashSet<Integer>();
        List<Machine> machines = findAll();
        for (Machine m : machines)
        {
            ids.add(m.getId());
        }
        return ids;
    }

    private static final String QUERY_ALL_IDS_IN =
        "SELECT m.id "
            + "FROM com.abiquo.server.core.infrastructure.Machine m WHERE m.datacenter IN (:datacenters)";

    /**
     * returns machien ids form selected datacenters
     */
    public List<Integer> findAllIdsInDatacenters(final Datacenter... datacenters)
    {
        Query query = getSession().createQuery(QUERY_ALL_IDS_IN);
        query.setParameterList("datacenters", datacenters);
        return query.list();
    }

    private static final String QUERY_TOTAL_USED_CORES = "SELECT sum(virtualCpuCores) "
        + "FROM com.abiquo.server.core.infrastructure.Machine";

    public Long getTotalUsedCores()
    {
        Query query = getSession().createQuery(QUERY_TOTAL_USED_CORES);
        Long result = (Long) query.uniqueResult();
        // If there are no results (no machines in DB) return 0
        return result == null ? 0L : result;
    }

    private static final String QUERY_USED_CORES_EXCEPT_MACHINE = "SELECT sum(virtualCpuCores) "
        + "FROM com.abiquo.server.core.infrastructure.Machine WHERE id != :id";

    public Long getTotalUsedCoresExceptMachine(final Machine machine)
    {
        Query query = getSession().createQuery(QUERY_USED_CORES_EXCEPT_MACHINE);
        query.setInteger("id", machine.getId());
        Long result = (Long) query.uniqueResult();
        // If there are no results (no other machines in DB) return 0
        return result == null ? 0L : result;
    }

    private static final String QUERY_BOOKABLE_MACHINES =
        "SELECT pm FROM Machine pm WHERE pm.id NOT IN"
            + " (SELECT DISTINCT pm.id FROM Machine pm, Hypervisor hy, VirtualMachine vm"
            + " WHERE vm.hypervisor.id = hy.id AND pm.id = hy.machine.id AND pm.rack.id = :rackId"
            + " AND vm.enterprise.id != :enterpriseId) AND pm.rack.id = :rackId AND pm.enterprise.id IS NULL";

    public List<Machine> findRackBookableMachines(final Rack rack, final Integer enterpriseId)
    {
        Query query = getSession().createQuery(QUERY_BOOKABLE_MACHINES);
        query.setParameter("rackId", rack.getId());
        query.setParameter("enterpriseId", enterpriseId);
        return query.list();
    }

    /**
     * TODO: This method is never called
     *
     * @param idRack
     * @param idVirtualDatacenter
     * @param enterprise
     * @return
     */
    // public List<Machine> findCandidateMachines(final Integer idRack,
    // final Integer idVirtualDatacenter, final Enterprise enterprise)
    // {
    //
    // List<Machine> machines;
    //
    // if (enterprise.getIsReservationRestricted())
    // {
    // machines =
    // findFirstCandidateMachinesReservedRestricted(idRack, idVirtualDatacenter,
    // enterprise);
    // }
    // else
    // {
    // machines = findFirstCandidateMachines(idRack, idVirtualDatacenter, enterprise);
    // }
    //
    // // StringBuilder sbcandidates = new StringBuilder();
    // List<Integer> candidatesids = new LinkedList<Integer>();
    // for (Machine m : machines)
    // {
    // candidatesids.add(m.getId());
    // }
    //
    // // execute the enterprise exclusion rule
    // Query excludedQuery = getSession().createQuery(QUERY_CANDIDATE_NO_ENTERPRISE_EXCLUDED);
    // excludedQuery.setParameter("enterpriseId", enterprise.getId());
    // List<Integer> excludedMachineIds = excludedQuery.list();
    //
    // List<Machine> notExcludedMachines = new LinkedList<Machine>();
    //
    // for (Machine m : machines)
    // {
    // Integer machineId = m.getId();
    //
    // if (!excludedMachineIds.contains(machineId))
    // {
    // notExcludedMachines.add(m);
    // }
    // }
    //
    // if (notExcludedMachines.size() == 0)
    // {
    // throw new
    // PersistenceException("All the candidate machines are excluded by other enterprises "
    // + "with virtual machines deployed on it. Please check the enterprise affinity rules.");
    // }
    //
    // return notExcludedMachines;
    // }

    private void whyNotCandidateMachines(final Integer idRack, final Integer idVirtualDatacenter,
        final Enterprise enterprise, final List<Integer> reserveds) throws PersistenceException
    {

        if (reserveds != null)
        {

            StringBuilder reservedMachinesB =
                new StringBuilder(String.format(
                    "Enterprise %s has the following machine reservations : ", enterprise.getName()));
            for (Integer mid : reserveds)
            {
                reservedMachinesB.append(mid + ' ');
            }

            /**
             * rack and hypervisor type
             */
            Query query1 =
                getSession().createQuery(WHY_QUERY_CANDIDATE_SAME_VDC_RACK_AND_TYPE_AND_RESERVED);
            query1.setInteger("idVirtualDataCenter", idVirtualDatacenter);
            query1.setInteger("idRack", idRack);
            query1.setParameterList("reserveds", reserveds);

            List<Integer> query1res = query1.list();

            if (query1res.size() == 0)
            {
                throw new PersistenceException(String.format(
                    "%s\nThere is no machine on the required rack [%d] and virtual datacenter [%d]. "
                        + "Please check the racks and hypervisor technology on the infrastructure.",
                    reservedMachinesB.toString(), idRack, idVirtualDatacenter));
            }

            throw new PersistenceException(String.format(
                "%s\nCould not find a MANAGED machine on rack [%d] and in virtual datacenter [%d]. "
                    + "Please check the machine health on the infrastructure.",
                reservedMachinesB.toString(), idRack, idVirtualDatacenter));

        } // reserved machines
        else
        {
            /**
             * rack and hypervisor type
             */
            Query query1 = getSession().createQuery(WHY_QUERY_CANDIDATE_SAME_VDC_RACK_AND_TYPE);
            query1.setInteger("idVirtualDataCenter", idVirtualDatacenter);
            query1.setInteger("idRack", idRack);

            List<Integer> query1res = query1.list();

            if (query1res.size() == 0)
            {
                throw new PersistenceException(String.format(
                    "There is no machine on the required rack [%d] and virtual datacenter [%d]. "
                        + "Please check the racks and hypervisor technology on the infrastructure.",
                    idRack, idVirtualDatacenter));
            }

            /**
             * rack, hypervisor type and managed state
             */
            Query query2 =
                getSession().createQuery(WHT_QUERY_CANDIDATE_SAME_VDC_RACK_AND_TYPE_AND_STATE);
            query2.setInteger("idVirtualDataCenter", idVirtualDatacenter);
            query2.setInteger("idRack", idRack);
            query2.setParameter("state", MachineState.MANAGED);

            List<Integer> query2res = query2.list();

            if (query2res.size() == 0)
            {
                throw new PersistenceException(String.format(
                    "Could not find a MANAGED machine on rack [%d] and in virtual datacenter [%d]. "
                        + "Please check the machine health on the infrastructure.", idRack,
                    idVirtualDatacenter));
            }

            throw new PersistenceException(String.format(
                "Could not find a MANAGED machine on rack [%d] and in virtual datacenter [%d] available for the current enterprise [%s]. "
                    + "Pleas check the machine reservation policies.", idRack, idVirtualDatacenter,
                enterprise.getName()));

        }
    }

    private List<Machine> findFirstCandidateMachinesReservedRestricted(final Integer idRack,
        final Integer idVirtualDatacenter, final Enterprise enterprise)
    {

        List<Machine> machines = null;

        List<Machine> reservMachines = findReservedMachines(enterprise);

        if (reservMachines != null && reservMachines.size() != 0)
        {
            List<Integer> reserveds = new LinkedList<Integer>();
            for (Machine m : reservMachines)
            {
                reserveds.add(m.getId());
            }

            Query query = getSession().createQuery(QUERY_CANDIDATE_MACHINES_RESERVED);
            query.setInteger("idVirtualDataCenter", idVirtualDatacenter);
            query.setInteger("idRack", idRack);
            query.setParameter("state", MachineState.MANAGED);
            query.setParameterList("reserveds", reserveds);

            machines = query.list();

            if (machines == null || machines.size() == 0)
            {
                whyNotCandidateMachines(idRack, idVirtualDatacenter, enterprise, reserveds);
            }

            return machines;
        }
        else
        {
            final String msg =
                String
                    .format(
                        "Enterprise works in restricted reserved machines mode but no machine is reserved. Current enterprise: %s",
                        enterprise.getName());

            throw new PersistenceException(msg);
        }
    }

    private List<Machine> findFirstCandidateMachines(final Integer idRack,
        final Integer idVirtualDatacenter, final Enterprise enterprise)
    {
        List<Machine> machines = null;

        Query query = getSession().createQuery(QUERY_CANDIDATE_MACHINES);

        query.setInteger("idVirtualDataCenter", idVirtualDatacenter);
        query.setInteger("idRack", idRack);
        query.setParameter("state", MachineState.MANAGED);
        query.setParameter("enterpriseId", enterprise.getId());

        machines = query.list();

        if (machines == null || machines.size() == 0)
        {
            whyNotCandidateMachines(idRack, idVirtualDatacenter, enterprise, null);
        }

        return machines;
    }

    @Override
    /**
     *
     */
    public void persist(final Machine entity)
    {
        // This asserts are needed for JpaDaoTestBase automated tests
        assert entity != null;
        assert isInReadWriteTransaction();

        getEntityManager().persist(entity);

        for (ScheduledResources sr : entity.getScheduledResources())
        {
            Datastore datastore = sr.getDatastore();
            if (datastore.getId() == null)
            {
                getEntityManager().persist(datastore);
            }
            sr.setDatastore(datastore);
            sr.setMachine(entity);
            getEntityManager().persist(sr);
        }

    }

}
TOP

Related Classes of com.abiquo.server.core.infrastructure.MachineDAO

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.