package org.ovirt.engine.core.dao; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import javax.inject.Named; import javax.inject.Singleton; import org.ovirt.engine.core.common.businessentities.AutoNumaBalanceStatus; import org.ovirt.engine.core.common.businessentities.ExternalStatus; import org.ovirt.engine.core.common.businessentities.KdumpStatus; import org.ovirt.engine.core.common.businessentities.NonOperationalReason; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.VDSStatus; import org.ovirt.engine.core.common.businessentities.VDSType; import org.ovirt.engine.core.common.businessentities.VdsSpmStatus; import org.ovirt.engine.core.common.businessentities.VdsTransparentHugePagesState; import org.ovirt.engine.core.common.businessentities.VmRngDevice; import org.ovirt.engine.core.common.businessentities.comparators.HostSpmPriorityComparator; import org.ovirt.engine.core.common.businessentities.gluster.PeerStatus; import org.ovirt.engine.core.common.businessentities.pm.FenceAgent; import org.ovirt.engine.core.common.utils.pm.FenceProxySourceTypeHelper; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.RpmVersion; import org.ovirt.engine.core.dal.dbbroker.DbFacadeUtils; import org.ovirt.engine.core.utils.serialization.json.JsonObjectDeserializer; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; /** * {@code VdsDaoImpl} provides an implementation of {@code VdsDao}. */ @Named @Singleton public class VdsDaoImpl extends BaseDao implements VdsDao { @Override public VDS get(Guid id) { return get(id, null, false); } @Override public VDS get(Guid id, Guid userID, boolean isFiltered) { // several rows may be returned because of join with fence agents table. List<VDS> vdsList = getCallsHandler().executeReadList("GetVdsByVdsId", vdsRowMapper, getCustomMapSqlParameterSource() .addValue("vds_id", id) .addValue("user_id", userID) .addValue("is_filtered", isFiltered)); return vdsList.size() == 0 ? null : uniteAgentsSingleVds(vdsList); } @Override public VDS getByName(String name) { List<VDS> vdsList = getCallsHandler().executeReadList("GetVdsByName", vdsRowMapper, getCustomMapSqlParameterSource() .addValue("vds_name", name)); return vdsList.size() == 0 ? null : uniteAgentsSingleVds(vdsList); } @Override public List<VDS> getAllForHostname(String hostname) { List<VDS> vdsList = getCallsHandler().executeReadList("GetVdsByHostName", vdsRowMapper, getCustomMapSqlParameterSource() .addValue("host_name", hostname)); return uniteAgents(vdsList); } @Override public List<VDS> getAllWithUniqueId(String id) { List<VDS> vdsList = getCallsHandler().executeReadList("GetVdsByUniqueID", vdsRowMapper, getCustomMapSqlParameterSource() .addValue("vds_unique_id", id)); return uniteAgents(vdsList); } @Override public List<VDS> getAllOfTypes(VDSType[] types) { List<VDS> list = new ArrayList<>(); for (VDSType type : types) { list.addAll(getAllOfType(type)); } return list; } @Override public List<VDS> getAllOfType(VDSType type) { List<VDS> vdsList = getCallsHandler().executeReadList("GetVdsByType", vdsRowMapper, getCustomMapSqlParameterSource() .addValue("vds_type", type)); return uniteAgents(vdsList); } @Override public List<VDS> getAllForClusterWithoutMigrating(Guid clusterId) { List<VDS> vdsList = getCallsHandler().executeReadList("GetVdsWithoutMigratingVmsByClusterId", vdsRowMapper, getCustomMapSqlParameterSource() .addValue("cluster_id", clusterId)); return uniteAgents(vdsList); } @Override public List<VDS> getAllWithQuery(String query) { List<VDS> vdsList = getJdbcTemplate().query(query, vdsRowMapper); return uniteAgents(vdsList); } @Override public List<VDS> getAll() { return getAll(null, false); } @Override public List<VDS> getAll(Guid userID, boolean isFiltered) { List<VDS> vdsList = getCallsHandler().executeReadList("GetAllFromVds", vdsRowMapper, getCustomMapSqlParameterSource().addValue("user_id", userID).addValue("is_filtered", isFiltered)); return uniteAgents(vdsList); } @Override public List<VDS> getAllForCluster(Guid cluster) { return getAllForCluster(cluster, null, false); } @Override public List<VDS> getAllForCluster(Guid cluster, Guid userID, boolean isFiltered) { List<VDS> vdsList = getCallsHandler().executeReadList("GetVdsByClusterId", vdsRowMapper, getCustomMapSqlParameterSource() .addValue("cluster_id", cluster) .addValue("user_id", userID) .addValue("is_filtered", isFiltered)); return uniteAgents(vdsList); } @Override public List<VDS> getHostsForStorageOperation(Guid storagePoolId, boolean localFsOnly) { // normalize to uniquely represent in DB that we want candidates from all DC's if (storagePoolId == null || storagePoolId.equals(Guid.Empty)) { storagePoolId = null; } List<VDS> vdsList = getCallsHandler().executeReadList("getHostsForStorageOperation", vdsRowMapper, getCustomMapSqlParameterSource() .addValue("storage_pool_id", storagePoolId) .addValue("local_fs_only", localFsOnly)); return uniteAgents(vdsList); } @Override public VDS getFirstUpRhelForCluster(Guid clsuterId) { List<VDS> vds = getCallsHandler().executeReadList("getFirstUpRhelForClusterId", vdsRowMapper, getCustomMapSqlParameterSource() .addValue("cluster_id", clsuterId)); return vds.size() != 0 ? vds.iterator().next() : null; } @Override public List<VDS> getAllForStoragePool(Guid storagePool) { return getAllForStoragePool(storagePool, null, false); } @Override public List<VDS> getAllForStoragePool(Guid storagePool, Guid userID, boolean isFiltered) { List<VDS> vdsList = getCallsHandler().executeReadList("GetVdsByStoragePoolId", vdsRowMapper, getCustomMapSqlParameterSource() .addValue("storage_pool_id", storagePool) .addValue("user_id", userID) .addValue("is_filtered", isFiltered)); return uniteAgents(vdsList); } @Override public List<VDS> getAllForClusterWithStatus(Guid clusterId, VDSStatus status) { List<VDS> vdsList = getCallsHandler().executeReadList("getVdsForClusterWithStatus", vdsRowMapper, getCustomMapSqlParameterSource() .addValue("cluster_id", clusterId) .addValue("status", status.getValue())); return uniteAgents(vdsList); } @Override public List<VDS> getAllForClusterWithStatusAndPeerStatus(Guid clusterId, VDSStatus status, PeerStatus peerStatus) { List<VDS> vdsList = getCallsHandler().executeReadList("getVdsForClusterWithPeerStatus", vdsRowMapper, getCustomMapSqlParameterSource() .addValue("cluster_id", clusterId) .addValue("status", status.getValue()) .addValue("peer_status", peerStatus.name())); return uniteAgents(vdsList); } @Override public List<VDS> getAllForStoragePoolAndStatus(Guid storagePool, VDSStatus status) { return getAllForStoragePoolAndStatuses(storagePool, status != null ? EnumSet.of(status) : null); } @Override public List<VDS> getAllForStoragePoolAndStatuses(Guid storagePool, Set<VDSStatus> statuses) { List<VDS> vdsList = getCallsHandler().executeReadList("getVdsByStoragePoolIdWithStatuses", vdsRowMapper, getCustomMapSqlParameterSource() .addValue("storage_pool_id", storagePool) .addValue("statuses", statuses == null? null : statuses.stream() .map(VDSStatus::getValue) .map(Object::toString) .collect(Collectors.joining(",")))); return uniteAgents(vdsList); } @Override public List<VDS> getListForSpmSelection(Guid storagePoolId) { List<VDS> vdsList = getCallsHandler().executeReadList("GetUpAndPrioritizedVds", vdsRowMapper, getCustomMapSqlParameterSource().addValue("storage_pool_id", storagePoolId)); return uniteAgentsPreserveSpmPrioritySorting(vdsList); } @Override public List<VDS> listFailedAutorecoverables() { List<VDS> vdsList = getCallsHandler().executeReadList("GetFailingVdss", vdsRowMapper, null); return uniteAgents(vdsList); } @Override public List<VDS> getAllForNetwork(Guid networkId) { MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource() .addValue("network_id", networkId); List<VDS> vdsList = getCallsHandler().executeReadList("GetVdsByNetworkId", vdsRowMapper, parameterSource); return uniteAgents(vdsList); } @Override public List<VDS> getAllWithoutNetwork(Guid networkId) { MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource() .addValue("network_id", networkId); List<VDS> vdsList = getCallsHandler().executeReadList("GetVdsWithoutNetwork", vdsRowMapper, parameterSource); return uniteAgents(vdsList); } private static final RowMapper<VDS> vdsRowMapper = (rs, rowNum) -> { final VDS entity = new VDS(); entity.setId(getGuidDefaultEmpty(rs, "vds_id")); entity.setClusterId(getGuidDefaultEmpty(rs, "cluster_id")); entity.setClusterName(rs.getString("cluster_name")); entity.setClusterDescription(rs.getString("cluster_description")); entity.setVdsName(rs.getString("vds_name")); entity.setComment(rs.getString("free_text_comment")); entity.setUniqueId(rs.getString("vds_unique_id")); entity.setServerSslEnabled(rs.getBoolean("server_SSL_enabled")); entity.setHostName(rs.getString("host_name")); entity.setPort(rs.getInt("port")); entity.setSshPort(rs.getInt("ssh_port")); entity.setSshUsername(rs.getString("ssh_username")); entity.setStatus(VDSStatus.forValue(rs.getInt("status"))); entity.setExternalStatus(ExternalStatus.forValue(rs.getInt("external_status"))); entity.setCpuCores((Integer) rs.getObject("cpu_cores")); entity.setCpuThreads((Integer) rs.getObject("cpu_threads")); entity.setCpuModel(rs.getString("cpu_model")); entity.setOnlineCpus(rs.getString("online_cpus")); entity.setCpuUser(rs.getDouble("cpu_user")); entity.setCpuSpeedMh(rs.getDouble("cpu_speed_mh")); entity.setIfTotalSpeed(rs.getString("if_total_speed")); entity.setKvmEnabled((Boolean) rs.getObject("kvm_enabled")); entity.setPhysicalMemMb((Integer) rs.getObject("physical_mem_mb")); entity.setCpuIdle(rs.getDouble("cpu_idle")); entity.setCpuLoad(rs.getDouble("cpu_load")); entity.setCpuSys(rs.getDouble("cpu_sys")); entity.setMemCommited((Integer) rs.getObject("mem_commited")); entity.setVmActive((Integer) rs.getObject("vm_active")); entity.setVmCount((Integer) rs.getObject("vm_count")); entity.setVmsCoresCount((Integer) rs.getObject("vms_cores_count")); entity.setVmMigrating((Integer) rs.getObject("vm_migrating")); entity.setIncomingMigrations(rs.getInt("incoming_migrations")); entity.setOutgoingMigrations(rs.getInt("outgoing_migrations")); entity.setUsageCpuPercent((Integer) rs.getObject("usage_cpu_percent")); entity.setUsageMemPercent((Integer) rs.getObject("usage_mem_percent")); entity.setUsageNetworkPercent((Integer) rs.getObject("usage_network_percent")); entity.setReservedMem((Integer) rs.getObject("reserved_mem")); entity.setGuestOverhead((Integer) rs.getObject("guest_overhead")); entity.setVersion(new RpmVersion(rs.getString("rpm_version"))); entity.setSoftwareVersion(rs.getString("software_version")); entity.setVersionName(rs.getString("version_name")); entity.setPreviousStatus(VDSStatus.forValue(rs.getInt("previous_status"))); entity.setMemAvailable(rs.getLong("mem_available")); entity.setMemShared(rs.getLong("mem_shared")); entity.setMemFree(rs.getLong("mem_free")); entity.setVdsType(VDSType.forValue(rs.getInt("vds_type"))); entity.setCpuFlags(rs.getString("cpu_flags")); entity.setClusterCpuName(rs.getString("cluster_cpu_name")); entity.setStoragePoolId(getGuidDefaultEmpty(rs, "storage_pool_id")); entity.setStoragePoolName(rs.getString("storage_pool_name")); entity.setPendingVcpusCount((Integer) rs.getObject("pending_vcpus_count")); entity.setCpuOverCommitTimestamp(DbFacadeUtils.fromDate(rs.getTimestamp("cpu_over_commit_time_stamp"))); entity.setPendingVmemSize(rs.getInt("pending_vmem_size")); entity.setVdsStrength(rs.getInt("vds_strength")); entity.setMaxVdsMemoryOverCommit(rs.getInt("max_vds_memory_over_commit")); entity.setCpuSockets((Integer) rs.getObject("cpu_sockets")); entity.setVdsSpmId((Integer) rs.getObject("vds_spm_id")); entity.setNetConfigDirty((Boolean) rs.getObject("net_config_dirty")); entity.setPmEnabled(rs.getBoolean("pm_enabled")); entity.setFenceProxySources(FenceProxySourceTypeHelper.parseFromString(rs.getString("pm_proxy_preferences"))); entity.setPmKdumpDetection(rs.getBoolean("pm_detect_kdump")); entity.setSpmStatus(VdsSpmStatus.forValue(rs.getInt("spm_status"))); entity.setSwapFree(rs.getLong("swap_free")); entity.setSwapTotal(rs.getLong("swap_total")); entity.setKsmCpuPercent((Integer) rs.getObject("ksm_cpu_percent")); entity.setKsmPages(rs.getLong("ksm_pages")); entity.setKsmState((Boolean) rs.getObject("ksm_state")); entity.setSupportedClusterLevels(rs.getString("supported_cluster_levels")); entity.setSupportedEngines(rs.getString("supported_engines")); entity.setClusterCompatibilityVersion(new VersionRowMapper("cluster_compatibility_version").mapRow(rs, rowNum)); entity.setClusterSupportsVirtService(rs.getBoolean("cluster_virt_service")); entity.setClusterSupportsGlusterService(rs.getBoolean("cluster_gluster_service")); entity.setHostOs(rs.getString("host_os")); entity.setGlusterVersion(new RpmVersion(rs.getString("gluster_version"))); entity.setLibrbdVersion(new RpmVersion(rs.getString("librbd1_version"))); entity.setGlusterfsCliVersion(new RpmVersion(rs.getString("glusterfs_cli_version"))); entity.setKvmVersion(rs.getString("kvm_version")); entity.setLibvirtVersion(new RpmVersion(rs.getString("libvirt_version"))); entity.setSpiceVersion(rs.getString("spice_version")); entity.setKernelVersion(rs.getString("kernel_version")); entity.setIScsiInitiatorName(rs.getString("iscsi_initiator_name")); entity.setTransparentHugePagesState(VdsTransparentHugePagesState .forValue(rs.getInt("transparent_hugepages_state"))); entity.setAnonymousHugePages(rs.getInt("anonymous_hugepages")); entity.setHooksStr(rs.getString("hooks")); entity.setNonOperationalReason(NonOperationalReason.forValue(rs.getInt("non_operational_reason"))); entity.setOtpValidity(rs.getLong("otp_validity")); entity.setVdsSpmPriority(rs.getInt("vds_spm_priority")); entity.setAutoRecoverable(rs.getBoolean("recoverable")); entity.setSshKeyFingerprint(rs.getString("sshKeyFingerprint")); entity.setHostProviderId(getGuid(rs, "host_provider_id")); entity.setHardwareManufacturer(rs.getString("hw_manufacturer")); entity.setHardwareProductName(rs.getString("hw_product_name")); entity.setHardwareVersion(rs.getString("hw_version")); entity.setHardwareSerialNumber(rs.getString("hw_serial_number")); entity.setHardwareUUID(rs.getString("hw_uuid")); entity.setHardwareFamily(rs.getString("hw_family")); entity.setHBAs(new JsonObjectDeserializer().deserialize(rs.getString("hbas"), HashMap.class)); entity.setConsoleAddress(rs.getString("console_address")); entity.setSupportedEmulatedMachines(rs.getString("supported_emulated_machines")); entity.setHighlyAvailableScore(rs.getInt("ha_score")); entity.setDisablePowerManagementPolicy(rs.getBoolean("disable_auto_pm")); entity.setPowerManagementControlledByPolicy(rs.getBoolean("controlled_by_pm_policy")); entity.setHighlyAvailableIsConfigured(rs.getBoolean("ha_configured")); entity.setHighlyAvailableIsActive(rs.getBoolean("ha_active")); entity.setHighlyAvailableGlobalMaintenance(rs.getBoolean("ha_global_maintenance")); entity.setHighlyAvailableLocalMaintenance(rs.getBoolean("ha_local_maintenance")); entity.setKdumpStatus(KdumpStatus.valueOfNumber(rs.getInt("kdump_status"))); entity.getSupportedRngSources().addAll(VmRngDevice.csvToSourcesSet(rs.getString("supported_rng_sources"))); entity.setBootTime((Long) rs.getObject("boot_time")); entity.setSELinuxEnforceMode((Integer) rs.getObject("selinux_enforce_mode")); entity.setAutoNumaBalancing(AutoNumaBalanceStatus.forValue(rs.getInt("auto_numa_balancing"))); entity.setNumaSupport(rs.getBoolean("is_numa_supported")); entity.setBalloonEnabled(rs.getBoolean("enable_balloon")); entity.setCountThreadsAsCores(rs.getBoolean("count_threads_as_cores")); entity.setMaintenanceReason(rs.getString("maintenance_reason")); entity.getStaticData().setOpenstackNetworkProviderId(getGuid(rs, "openstack_network_provider_id")); Guid agentGuid = getGuid(rs, "agent_id"); if (agentGuid != null) { FenceAgent agent = new FenceAgent(); agent.setId(agentGuid); agent.setHostId(getGuid(rs, "vds_id")); agent.setOrder(rs.getInt("agent_order")); agent.setType(rs.getString("agent_type")); agent.setUser(rs.getString("agent_user")); agent.setPassword(DbFacadeUtils.decryptPassword(rs.getString("agent_password"))); int port = rs.getInt("agent_port"); agent.setPort(port == 0 ? null : port); agent.setEncryptOptions(rs.getBoolean("agent_encrypt_options")); if (agent.getEncryptOptions()) { agent.setOptions(DbFacadeUtils.decryptPassword(rs.getString("agent_options"))); } else { agent.setOptions(rs.getString("agent_options")); } agent.setIp(rs.getString("agent_ip")); entity.getFenceAgents().add(agent); } entity.setUpdateAvailable(rs.getBoolean("is_update_available")); entity.setHostDevicePassthroughEnabled(rs.getBoolean("is_hostdev_enabled")); entity.setHostedEngineHost(rs.getBoolean("is_hosted_engine_host")); VdsStaticDaoImpl.KernelCmdlineColumn.fromJson(rs.getString("kernel_cmdline")).toVds(entity); entity.setLastStoredKernelCmdline(rs.getString("last_stored_kernel_cmdline")); entity.setKernelArgs(rs.getString("kernel_args")); entity.setFencingEnabled(rs.getBoolean("fencing_enabled")); entity.setGlusterPeerStatus(PeerStatus.fromValue(rs.getString("gluster_peer_status"))); entity.setPrettyName(rs.getString("pretty_name")); entity.setHostedEngineConfigured(rs.getBoolean("hosted_engine_configured")); return entity; }; /** * Unit the fence agents from potentially multiple VDS (they are the same VDS, they just have multiple rows * in the result set), while maintaining the order in which the VDSs were returned by the query. * @param vdsList The list of VDS (with potentially multiple VDS being the same with different fence agents). * @return A list of VDS where each VDS is unique (according to the GUID) and each VDS can contain potentially * multiple fence agents. */ private List<VDS> uniteAgents(List<VDS> vdsList) { Map<Guid, VDS> vdsMap = new HashMap<>(); List<VDS> results = new ArrayList<>(); for (VDS vds: vdsList) { Guid vdsId = vds.getId(); VDS usedVds = vdsMap.get(vdsId); if (usedVds == null) { results.add(vds); vdsMap.put(vdsId, vds); } else { usedVds.getFenceAgents().addAll(vds.getFenceAgents()); } } return results; } private VDS uniteAgentsSingleVds(List<VDS> vdsList) { return uniteAgents(vdsList).get(0); } private List<VDS> uniteAgentsPreserveSpmPrioritySorting(List<VDS> vdsList) { List<VDS> results = uniteAgents(vdsList); // Ensure that the list is ordered according to SPM priority DESC Collections.sort(results, new HostSpmPriorityComparator()); return results; } }