/**
* 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.host;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.HostNotFoundException;
import org.apache.ambari.server.agent.AgentEnv;
import org.apache.ambari.server.agent.DiskInfo;
import org.apache.ambari.server.agent.HostInfo;
import org.apache.ambari.server.agent.RecoveryReport;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.controller.HostResponse;
import org.apache.ambari.server.events.MaintenanceModeEvent;
import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
import org.apache.ambari.server.orm.cache.HostConfigMapping;
import org.apache.ambari.server.orm.cache.HostConfigMappingImpl;
import org.apache.ambari.server.orm.dao.ClusterDAO;
import org.apache.ambari.server.orm.dao.HostConfigMappingDAO;
import org.apache.ambari.server.orm.dao.HostDAO;
import org.apache.ambari.server.orm.dao.HostStateDAO;
import org.apache.ambari.server.orm.dao.HostVersionDAO;
import org.apache.ambari.server.orm.entities.ClusterEntity;
import org.apache.ambari.server.orm.entities.HostComponentStateEntity;
import org.apache.ambari.server.orm.entities.HostEntity;
import org.apache.ambari.server.orm.entities.HostStateEntity;
import org.apache.ambari.server.orm.entities.HostVersionEntity;
import org.apache.ambari.server.state.AgentVersion;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.ComponentInfo;
import org.apache.ambari.server.state.Config;
import org.apache.ambari.server.state.DesiredConfig;
import org.apache.ambari.server.state.Host;
import org.apache.ambari.server.state.HostConfig;
import org.apache.ambari.server.state.HostEvent;
import org.apache.ambari.server.state.HostEventType;
import org.apache.ambari.server.state.HostHealthStatus;
import org.apache.ambari.server.state.HostHealthStatus.HealthStatus;
import org.apache.ambari.server.state.HostState;
import org.apache.ambari.server.state.MaintenanceState;
import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.configgroup.ConfigGroup;
import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
import org.apache.ambari.server.state.fsm.SingleArcTransition;
import org.apache.ambari.server.state.fsm.StateMachine;
import org.apache.ambari.server.state.fsm.StateMachineFactory;
import org.apache.ambari.server.topology.TopologyManager;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.persist.Transactional;
public class HostImpl implements Host {
private static final Logger LOG = LoggerFactory.getLogger(HostImpl.class);
private static final String HARDWAREISA = "hardware_isa";
private static final String HARDWAREMODEL = "hardware_model";
private static final String INTERFACES = "interfaces";
private static final String KERNEL = "kernel";
private static final String KERNELMAJOREVERSON = "kernel_majorversion";
private static final String KERNELRELEASE = "kernel_release";
private static final String KERNELVERSION = "kernel_version";
private static final String MACADDRESS = "mac_address";
private static final String NETMASK = "netmask";
private static final String OSFAMILY = "os_family";
private static final String PHYSICALPROCESSORCOUNT = "physicalprocessors_count";
private static final String PROCESSORCOUNT = "processors_count";
private static final String SELINUXENABLED = "selinux_enabled";
private static final String SWAPSIZE = "swap_size";
private static final String SWAPFREE = "swap_free";
private static final String TIMEZONE = "timezone";
private static final String OS_RELEASE_VERSION = "os_release_version";
@Inject
private final Gson gson;
private static final Type hostAttributesType =
new TypeToken<Map<String, String>>() {}.getType();
private static final Type maintMapType =
new TypeToken<Map<Long, MaintenanceState>>() {}.getType();
ReadWriteLock rwLock;
private final Lock writeLock;
@Inject
private HostDAO hostDAO;
@Inject
private HostStateDAO hostStateDAO;
@Inject
private HostVersionDAO hostVersionDAO;
@Inject
private ClusterDAO clusterDAO;
@Inject
private Clusters clusters;
@Inject
private HostConfigMappingDAO hostConfigMappingDAO;
@Inject
private AmbariMetaInfo ambariMetaInfo;
/**
* The ID of the host which is to retrieve it from JPA.
*/
private final long hostId;
/**
* The name of the host, stored inside of this business object to prevent JPA
* lookups since it never changes.
*/
private final String hostName;
private long lastHeartbeatTime = 0L;
private AgentEnv lastAgentEnv = null;
private List<DiskInfo> disksInfo = new CopyOnWriteArrayList<>();
private RecoveryReport recoveryReport = new RecoveryReport();
private Integer currentPingPort = null;
private final StateMachine<HostState, HostEventType, HostEvent> stateMachine;
private final ConcurrentMap<Long, MaintenanceState> maintMap;
// In-memory status, based on host components states
private String status = HealthStatus.UNKNOWN.name();
// In-memory prefix of log file paths that is retrieved when the agent registers with the server
private String prefix;
/**
* Used to publish events relating to host CRUD operations.
*/
@Inject
private AmbariEventPublisher eventPublisher;
@Inject
private TopologyManager topologyManager;
private static final StateMachineFactory
<HostImpl, HostState, HostEventType, HostEvent>
stateMachineFactory
= new StateMachineFactory<HostImpl, HostState, HostEventType, HostEvent>
(HostState.INIT)
// define the state machine of a Host
// Transition from INIT state
// when the initial registration request is received
.addTransition(HostState.INIT, HostState.WAITING_FOR_HOST_STATUS_UPDATES,
HostEventType.HOST_REGISTRATION_REQUEST, new HostRegistrationReceived())
// when a heartbeat is lost right after registration
.addTransition(HostState.INIT, HostState.HEARTBEAT_LOST,
HostEventType.HOST_HEARTBEAT_LOST, new HostHeartbeatLostTransition())
// Transition from WAITING_FOR_STATUS_UPDATES state
// when the host has responded to its status update requests
// TODO this will create problems if the host is not healthy
// TODO Based on discussion with Jitendra, ignoring this for now
.addTransition(HostState.WAITING_FOR_HOST_STATUS_UPDATES, HostState.HEALTHY,
HostEventType.HOST_STATUS_UPDATES_RECEIVED,
new HostStatusUpdatesReceivedTransition())
// when a normal heartbeat is received
.addTransition(HostState.WAITING_FOR_HOST_STATUS_UPDATES,
HostState.WAITING_FOR_HOST_STATUS_UPDATES,
HostEventType.HOST_HEARTBEAT_HEALTHY) // TODO: Heartbeat is ignored here
// when a heartbeart denoting host as unhealthy is received
.addTransition(HostState.WAITING_FOR_HOST_STATUS_UPDATES,
HostState.WAITING_FOR_HOST_STATUS_UPDATES, // Still waiting for component status
HostEventType.HOST_HEARTBEAT_UNHEALTHY,
new HostBecameUnhealthyTransition()) // TODO: Not sure
// when a heartbeat is lost and status update is not received
.addTransition(HostState.WAITING_FOR_HOST_STATUS_UPDATES,
HostState.HEARTBEAT_LOST,
HostEventType.HOST_HEARTBEAT_LOST,
new HostHeartbeatLostTransition())
// Transitions from HEALTHY state
// when a normal heartbeat is received
.addTransition(HostState.HEALTHY, HostState.HEALTHY,
HostEventType.HOST_HEARTBEAT_HEALTHY,
new HostHeartbeatReceivedTransition())
// when a heartbeat is not received within the configured timeout period
.addTransition(HostState.HEALTHY, HostState.HEARTBEAT_LOST,
HostEventType.HOST_HEARTBEAT_LOST,
new HostHeartbeatLostTransition())
// when a heartbeart denoting host as unhealthy is received
.addTransition(HostState.HEALTHY, HostState.UNHEALTHY,
HostEventType.HOST_HEARTBEAT_UNHEALTHY,
new HostBecameUnhealthyTransition())
// if a new registration request is received
.addTransition(HostState.HEALTHY,
HostState.WAITING_FOR_HOST_STATUS_UPDATES,
HostEventType.HOST_REGISTRATION_REQUEST, new HostRegistrationReceived())
// Transitions from UNHEALTHY state
// when a normal heartbeat is received
.addTransition(HostState.UNHEALTHY, HostState.HEALTHY,
HostEventType.HOST_HEARTBEAT_HEALTHY,
new HostBecameHealthyTransition())
// when a heartbeart denoting host as unhealthy is received
.addTransition(HostState.UNHEALTHY, HostState.UNHEALTHY,
HostEventType.HOST_HEARTBEAT_UNHEALTHY,
new HostHeartbeatReceivedTransition())
// when a heartbeat is not received within the configured timeout period
.addTransition(HostState.UNHEALTHY, HostState.HEARTBEAT_LOST,
HostEventType.HOST_HEARTBEAT_LOST,
new HostHeartbeatLostTransition())
// if a new registration request is received
.addTransition(HostState.UNHEALTHY,
HostState.WAITING_FOR_HOST_STATUS_UPDATES,
HostEventType.HOST_REGISTRATION_REQUEST, new HostRegistrationReceived())
// Transitions from HEARTBEAT_LOST state
// when a heartbeat is not received within the configured timeout period
.addTransition(HostState.HEARTBEAT_LOST, HostState.HEARTBEAT_LOST,
HostEventType.HOST_HEARTBEAT_LOST)
// if a new registration request is received
.addTransition(HostState.HEARTBEAT_LOST,
HostState.WAITING_FOR_HOST_STATUS_UPDATES,
HostEventType.HOST_REGISTRATION_REQUEST, new HostRegistrationReceived())
.installTopology();
@Inject
public HostImpl(@Assisted HostEntity hostEntity, Gson gson, HostDAO hostDAO, HostStateDAO hostStateDAO) {
this.gson = gson;
this.hostDAO = hostDAO;
this.hostStateDAO = hostStateDAO;
stateMachine = stateMachineFactory.make(this);
rwLock = new ReentrantReadWriteLock();
writeLock = rwLock.writeLock();
HostStateEntity hostStateEntity = hostEntity.getHostStateEntity();
if (hostStateEntity == null) {
hostStateEntity = new HostStateEntity();
hostStateEntity.setHostEntity(hostEntity);
hostEntity.setHostStateEntity(hostStateEntity);
hostStateEntity.setHealthStatus(gson.toJson(new HostHealthStatus(HealthStatus.UNKNOWN, "")));
} else {
stateMachine.setCurrentState(hostStateEntity.getCurrentState());
}
// persist the host
if (null == hostEntity.getHostId()) {
persistEntities(hostEntity);
for (ClusterEntity clusterEntity : hostEntity.getClusterEntities()) {
try {
clusters.getClusterById(clusterEntity.getClusterId()).refresh();
} catch (AmbariException e) {
LOG.error("Error while looking up the cluster", e);
throw new RuntimeException("Cluster '" + clusterEntity.getClusterId() + "' was removed",
e);
}
}
}
// set the host ID which will be used to retrieve it from JPA
hostId = hostEntity.getHostId();
hostName = hostEntity.getHostName();
// populate the maintenance map
maintMap = ensureMaintMap(hostEntity.getHostStateEntity());
}
@Override
public int compareTo(Object o) {
if ((o != null ) && (o instanceof Host)) {
return getHostName().compareTo(((Host) o).getHostName());
} else {
return -1;
}
}
static class HostRegistrationReceived
implements SingleArcTransition<HostImpl, HostEvent> {
@Override
public void transition(HostImpl host, HostEvent event) {
HostRegistrationRequestEvent e = (HostRegistrationRequestEvent) event;
host.importHostInfo(e.hostInfo);
host.setLastRegistrationTime(e.registrationTime);
//Initialize heartbeat time and timeInState with registration time.
host.setLastHeartbeatTime(e.registrationTime);
host.setLastAgentEnv(e.agentEnv);
host.setTimeInState(e.registrationTime);
host.setAgentVersion(e.agentVersion);
host.setPublicHostName(e.publicHostName);
String agentVersion = null;
if (e.agentVersion != null) {
agentVersion = e.agentVersion.getVersion();
}
LOG.info("Received host registration, host="
+ e.hostInfo.toString()
+ ", registrationTime=" + e.registrationTime
+ ", agentVersion=" + agentVersion);
host.clusters.updateHostMappings(host);
//todo: proper host joined notification
boolean associatedWithCluster = false;
try {
associatedWithCluster = host.clusters.getClustersForHost(host.getPublicHostName()).size() > 0;
} catch (HostNotFoundException e1) {
associatedWithCluster = false;
} catch (AmbariException e1) {
// only HostNotFoundException is thrown
LOG.error("Unable to determine the clusters for host", e1);
}
host.topologyManager.onHostRegistered(host, associatedWithCluster);
}
}
static class HostStatusUpdatesReceivedTransition
implements SingleArcTransition<HostImpl, HostEvent> {
@Override
public void transition(HostImpl host, HostEvent event) {
HostStatusUpdatesReceivedEvent e = (HostStatusUpdatesReceivedEvent)event;
// TODO Audit logs
LOG.debug("Host transition to host status updates received state"
+ ", host=" + e.getHostName()
+ ", heartbeatTime=" + e.getTimestamp());
host.setHealthStatus(new HostHealthStatus(HealthStatus.HEALTHY,
host.getHealthStatus().getHealthReport()));
}
}
static class HostHeartbeatReceivedTransition
implements SingleArcTransition<HostImpl, HostEvent> {
@Override
public void transition(HostImpl host, HostEvent event) {
long heartbeatTime = 0;
switch (event.getType()) {
case HOST_HEARTBEAT_HEALTHY:
HostHealthyHeartbeatEvent hhevent = (HostHealthyHeartbeatEvent) event;
heartbeatTime = hhevent.getHeartbeatTime();
if (null != hhevent.getAgentEnv()) {
host.setLastAgentEnv(hhevent.getAgentEnv());
}
if (null != hhevent.getMounts() && !hhevent.getMounts().isEmpty()) {
host.setDisksInfo(hhevent.getMounts());
}
break;
case HOST_HEARTBEAT_UNHEALTHY:
heartbeatTime =
((HostUnhealthyHeartbeatEvent)event).getHeartbeatTime();
break;
default:
break;
}
if (0 == heartbeatTime) {
LOG.error("heartbeatTime = 0 !!!");
// TODO handle error
}
// host.setLastHeartbeatState(new Object());
host.setLastHeartbeatTime(heartbeatTime);
}
}
static class HostBecameHealthyTransition
implements SingleArcTransition<HostImpl, HostEvent> {
@Override
public void transition(HostImpl host, HostEvent event) {
HostHealthyHeartbeatEvent e = (HostHealthyHeartbeatEvent) event;
host.setLastHeartbeatTime(e.getHeartbeatTime());
// TODO Audit logs
LOG.debug("Host transitioned to a healthy state"
+ ", host=" + e.getHostName()
+ ", heartbeatTime=" + e.getHeartbeatTime());
host.setHealthStatus(new HostHealthStatus(HealthStatus.HEALTHY, host.getHealthStatus().getHealthReport()));
}
}
static class HostBecameUnhealthyTransition
implements SingleArcTransition<HostImpl, HostEvent> {
@Override
public void transition(HostImpl host, HostEvent event) {
HostUnhealthyHeartbeatEvent e = (HostUnhealthyHeartbeatEvent) event;
host.setLastHeartbeatTime(e.getHeartbeatTime());
// TODO Audit logs
LOG.debug("Host transitioned to an unhealthy state"
+ ", host=" + e.getHostName()
+ ", heartbeatTime=" + e.getHeartbeatTime()
+ ", healthStatus=" + e.getHealthStatus());
host.setHealthStatus(e.getHealthStatus());
}
}
static class HostHeartbeatLostTransition
implements SingleArcTransition<HostImpl, HostEvent> {
@Override
public void transition(HostImpl host, HostEvent event) {
HostHeartbeatLostEvent e = (HostHeartbeatLostEvent) event;
// TODO Audit logs
LOG.debug("Host transitioned to heartbeat lost state"
+ ", host=" + e.getHostName()
+ ", lastHeartbeatTime=" + host.getLastHeartbeatTime());
host.setHealthStatus(new HostHealthStatus(HealthStatus.UNKNOWN, host.getHealthStatus().getHealthReport()));
host.topologyManager.onHostHeartBeatLost(host);
}
}
/**
* @param hostInfo the host information
*/
@Override
@Transactional
public void importHostInfo(HostInfo hostInfo) {
if (hostInfo.getIPAddress() != null && !hostInfo.getIPAddress().isEmpty()) {
setIPv4(hostInfo.getIPAddress());
setIPv6(hostInfo.getIPAddress());
}
setCpuCount(hostInfo.getProcessorCount());
setPhCpuCount(hostInfo.getPhysicalProcessorCount());
setTotalMemBytes(hostInfo.getMemoryTotal());
setAvailableMemBytes(hostInfo.getFreeMemory());
if (hostInfo.getArchitecture() != null && !hostInfo.getArchitecture().isEmpty()) {
setOsArch(hostInfo.getArchitecture());
}
if (hostInfo.getOS() != null && !hostInfo.getOS().isEmpty()) {
String osType = hostInfo.getOS();
if (hostInfo.getOSRelease() != null) {
String[] release = hostInfo.getOSRelease().split("\\.");
if (release.length > 0) {
osType += release[0];
}
}
setOsType(osType.toLowerCase());
}
if (hostInfo.getMounts() != null && !hostInfo.getMounts().isEmpty()) {
setDisksInfo(hostInfo.getMounts());
}
// FIXME add all other information into host attributes
setAgentVersion(new AgentVersion(hostInfo.getAgentUserId()));
Map<String, String> attrs = new HashMap<>();
if (hostInfo.getHardwareIsa() != null) {
attrs.put(HARDWAREISA, hostInfo.getHardwareIsa());
}
if (hostInfo.getHardwareModel() != null) {
attrs.put(HARDWAREMODEL, hostInfo.getHardwareModel());
}
if (hostInfo.getInterfaces() != null) {
attrs.put(INTERFACES, hostInfo.getInterfaces());
}
if (hostInfo.getKernel() != null) {
attrs.put(KERNEL, hostInfo.getKernel());
}
if (hostInfo.getKernelMajVersion() != null) {
attrs.put(KERNELMAJOREVERSON, hostInfo.getKernelMajVersion());
}
if (hostInfo.getKernelRelease() != null) {
attrs.put(KERNELRELEASE, hostInfo.getKernelRelease());
}
if (hostInfo.getKernelVersion() != null) {
attrs.put(KERNELVERSION, hostInfo.getKernelVersion());
}
if (hostInfo.getMacAddress() != null) {
attrs.put(MACADDRESS, hostInfo.getMacAddress());
}
if (hostInfo.getNetMask() != null) {
attrs.put(NETMASK, hostInfo.getNetMask());
}
if (hostInfo.getOSFamily() != null) {
attrs.put(OSFAMILY, hostInfo.getOSFamily());
}
if (hostInfo.getPhysicalProcessorCount() != 0) {
attrs.put(PHYSICALPROCESSORCOUNT, Long.toString(hostInfo.getPhysicalProcessorCount()));
}
if (hostInfo.getProcessorCount() != 0) {
attrs.put(PROCESSORCOUNT, Long.toString(hostInfo.getProcessorCount()));
}
if (Boolean.toString(hostInfo.getSeLinux()) != null) {
attrs.put(SELINUXENABLED, Boolean.toString(hostInfo.getSeLinux()));
}
if (hostInfo.getSwapSize() != null) {
attrs.put(SWAPSIZE, hostInfo.getSwapSize());
}
if (hostInfo.getSwapFree() != null) {
attrs.put(SWAPFREE, hostInfo.getSwapFree());
}
if (hostInfo.getTimeZone() != null) {
attrs.put(TIMEZONE, hostInfo.getTimeZone());
}
if (hostInfo.getOSRelease() != null) {
attrs.put(OS_RELEASE_VERSION, hostInfo.getOSRelease());
}
setHostAttributes(attrs);
}
@Override
public void setLastAgentEnv(AgentEnv env) {
lastAgentEnv = env;
}
@Override
public AgentEnv getLastAgentEnv() {
return lastAgentEnv;
}
@Override
public HostState getState() {
return stateMachine.getCurrentState();
}
@Override
public void setState(HostState state) {
stateMachine.setCurrentState(state);
HostStateEntity hostStateEntity = getHostStateEntity();
if (hostStateEntity != null) {
hostStateEntity.setCurrentState(state);
hostStateEntity.setTimeInState(System.currentTimeMillis());
hostStateDAO.merge(hostStateEntity);
}
}
@Override
public void handleEvent(HostEvent event)
throws InvalidStateTransitionException {
if (LOG.isDebugEnabled()) {
LOG.debug("Handling Host event, eventType=" + event.getType().name()
+ ", event=" + event.toString());
}
HostState oldState = getState();
try {
writeLock.lock();
try {
stateMachine.doTransition(event.getType(), event);
} catch (InvalidStateTransitionException e) {
LOG.error("Can't handle Host event at current state"
+ ", host=" + getHostName()
+ ", currentState=" + oldState
+ ", eventType=" + event.getType()
+ ", event=" + event);
throw e;
}
}
finally {
writeLock.unlock();
}
if (oldState != getState()) {
if (LOG.isDebugEnabled()) {
LOG.debug("Host transitioned to a new state"
+ ", host=" + getHostName()
+ ", oldState=" + oldState
+ ", currentState=" + getState()
+ ", eventType=" + event.getType().name()
+ ", event=" + event);
}
}
}
@Override
public String getHostName() {
return hostName;
}
@Override
public Long getHostId() {
return hostId;
}
@Override
public Integer getCurrentPingPort() {
return currentPingPort;
}
@Override
public void setCurrentPingPort(Integer currentPingPort) {
this.currentPingPort = currentPingPort;
}
@Override
public void setPublicHostName(String hostName) {
HostEntity hostEntity = getHostEntity();
hostEntity.setPublicHostName(hostName);
hostDAO.merge(hostEntity);
}
@Override
public String getPublicHostName() {
return getHostEntity().getPublicHostName();
}
@Override
public String getIPv4() {
return getHostEntity().getIpv4();
}
@Override
public void setIPv4(String ip) {
HostEntity hostEntity = getHostEntity();
hostEntity.setIpv4(ip);
hostDAO.merge(hostEntity);
}
@Override
public String getIPv6() {
return getHostEntity().getIpv6();
}
@Override
public void setIPv6(String ip) {
HostEntity hostEntity = getHostEntity();
hostEntity.setIpv6(ip);
hostDAO.merge(hostEntity);
}
@Override
public int getCpuCount() {
return getHostEntity().getCpuCount();
}
@Override
public void setCpuCount(int cpuCount) {
HostEntity hostEntity = getHostEntity();
hostEntity.setCpuCount(cpuCount);
hostDAO.merge(hostEntity);
}
@Override
public int getPhCpuCount() {
return getHostEntity().getPhCpuCount();
}
@Override
public void setPhCpuCount(int phCpuCount) {
HostEntity hostEntity = getHostEntity();
hostEntity.setPhCpuCount(phCpuCount);
hostDAO.merge(hostEntity);
}
@Override
public long getTotalMemBytes() {
return getHostEntity().getTotalMem();
}
@Override
public void setTotalMemBytes(long totalMemBytes) {
HostEntity hostEntity = getHostEntity();
hostEntity.setTotalMem(totalMemBytes);
hostDAO.merge(hostEntity);
}
@Override
public long getAvailableMemBytes() {
HostStateEntity hostStateEntity = getHostStateEntity();
return hostStateEntity != null ? hostStateEntity.getAvailableMem() : 0;
}
@Override
public void setAvailableMemBytes(long availableMemBytes) {
HostStateEntity hostStateEntity = getHostStateEntity();
if (hostStateEntity != null) {
hostStateEntity.setAvailableMem(availableMemBytes);
hostStateDAO.merge(hostStateEntity);
}
}
@Override
public String getOsArch() {
return getHostEntity().getOsArch();
}
@Override
public void setOsArch(String osArch) {
HostEntity hostEntity = getHostEntity();
hostEntity.setOsArch(osArch);
hostDAO.merge(hostEntity);
}
@Override
public String getOsInfo() {
return getHostEntity().getOsInfo();
}
@Override
public void setOsInfo(String osInfo) {
HostEntity hostEntity = getHostEntity();
hostEntity.setOsInfo(osInfo);
hostDAO.merge(hostEntity);
}
@Override
public String getOsType() {
return getHostEntity().getOsType();
}
@Override
public void setOsType(String osType) {
HostEntity hostEntity = getHostEntity();
hostEntity.setOsType(osType);
hostDAO.merge(hostEntity);
}
@Override
public String getOsFamily() {
Map<String, String> hostAttributes = getHostAttributes();
return getOSFamilyFromHostAttributes(hostAttributes);
}
@Override
public String getOSFamilyFromHostAttributes(Map<String, String> hostAttributes) {
try {
String majorVersion = hostAttributes.get(OS_RELEASE_VERSION).split("\\.")[0];
return hostAttributes.get(OSFAMILY) + majorVersion;
} catch(Exception e) {
LOG.error("Error while getting os family from host attributes:", e);
}
return null;
}
@Override
public List<DiskInfo> getDisksInfo() {
return disksInfo;
}
@Override
public void setDisksInfo(List<DiskInfo> disksInfo) {
this.disksInfo = disksInfo;
}
@Override
public RecoveryReport getRecoveryReport() {
return recoveryReport;
}
@Override
public void setRecoveryReport(RecoveryReport recoveryReport) {
this.recoveryReport = recoveryReport;
}
@Override
public HostHealthStatus getHealthStatus() {
HostStateEntity hostStateEntity = getHostStateEntity();
if (hostStateEntity != null) {
return gson.fromJson(hostStateEntity.getHealthStatus(), HostHealthStatus.class);
}
return null;
}
@Override
public void setHealthStatus(HostHealthStatus healthStatus) {
HostStateEntity hostStateEntity = getHostStateEntity();
if (hostStateEntity != null) {
hostStateEntity.setHealthStatus(gson.toJson(healthStatus));
if (healthStatus.getHealthStatus().equals(HealthStatus.UNKNOWN)) {
setStatus(HealthStatus.UNKNOWN.name());
}
hostStateDAO.merge(hostStateEntity);
}
}
@Override
public String getPrefix() {
return prefix;
}
@Override
public void setPrefix(String prefix) {
if (StringUtils.isNotBlank(prefix) && !StringUtils.equals(this.prefix, prefix)) {
this.prefix = prefix;
}
}
@Override
public Map<String, String> getHostAttributes() {
return gson.fromJson(getHostEntity().getHostAttributes(), hostAttributesType);
}
@Override
public void setHostAttributes(Map<String, String> hostAttributes) {
HostEntity hostEntity = getHostEntity();
Map<String, String> hostAttrs = gson.fromJson(hostEntity.getHostAttributes(), hostAttributesType);
if (hostAttrs == null) {
hostAttrs = new ConcurrentHashMap<>();
}
hostAttrs.putAll(hostAttributes);
hostEntity.setHostAttributes(gson.toJson(hostAttrs,hostAttributesType));
hostDAO.merge(hostEntity);
}
@Override
public String getRackInfo() {
return getHostEntity().getRackInfo();
}
@Override
public void setRackInfo(String rackInfo) {
HostEntity hostEntity = getHostEntity();
hostEntity.setRackInfo(rackInfo);
hostDAO.merge(hostEntity);
}
@Override
public long getLastRegistrationTime() {
return getHostEntity().getLastRegistrationTime();
}
@Override
public void setLastRegistrationTime(long lastRegistrationTime) {
HostEntity hostEntity = getHostEntity();
hostEntity.setLastRegistrationTime(lastRegistrationTime);
hostDAO.merge(hostEntity);
}
@Override
public long getLastHeartbeatTime() {
return lastHeartbeatTime;
}
@Override
public void setLastHeartbeatTime(long lastHeartbeatTime) {
this.lastHeartbeatTime = lastHeartbeatTime;
}
@Override
public AgentVersion getAgentVersion() {
HostStateEntity hostStateEntity = getHostStateEntity();
if (hostStateEntity != null) {
return gson.fromJson(hostStateEntity.getAgentVersion(), AgentVersion.class);
}
return null;
}
@Override
public void setAgentVersion(AgentVersion agentVersion) {
HostStateEntity hostStateEntity = getHostStateEntity();
if (hostStateEntity != null) {
hostStateEntity.setAgentVersion(gson.toJson(agentVersion));
hostStateDAO.merge(hostStateEntity);
}
}
@Override
public long getTimeInState() {
HostStateEntity hostStateEntity = getHostStateEntity();
return hostStateEntity != null ? hostStateEntity.getTimeInState() : null;
}
@Override
public void setTimeInState(long timeInState) {
HostStateEntity hostStateEntity = getHostStateEntity();
if (hostStateEntity != null) {
hostStateEntity.setTimeInState(timeInState);
hostStateDAO.merge(hostStateEntity);
}
}
@Override
public String getStatus() {
return status;
}
@Override
public void setStatus(String status) {
this.status = status;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Host that = (Host) o;
return getHostName().equals(that.getHostName());
}
@Override
public int hashCode() {
return (null == getHostName() ? 0 : getHostName().hashCode());
}
@Override
public HostResponse convertToResponse() {
HostResponse r = new HostResponse(getHostName());
r.setAgentVersion(getAgentVersion());
r.setAvailableMemBytes(getAvailableMemBytes());
r.setPhCpuCount(getPhCpuCount());
r.setCpuCount(getCpuCount());
r.setDisksInfo(getDisksInfo());
r.setHealthStatus(getHealthStatus());
r.setHostAttributes(getHostAttributes());
r.setIpv4(getIPv4());
r.setIpv6(getIPv6());
r.setLastHeartbeatTime(getLastHeartbeatTime());
r.setLastAgentEnv(lastAgentEnv);
r.setLastRegistrationTime(getLastRegistrationTime());
r.setOsArch(getOsArch());
r.setOsInfo(getOsInfo());
r.setOsType(getOsType());
r.setRackInfo(getRackInfo());
r.setTotalMemBytes(getTotalMemBytes());
r.setPublicHostName(getPublicHostName());
r.setHostState(getState().toString());
r.setStatus(getStatus());
r.setRecoveryReport(getRecoveryReport());
r.setRecoverySummary(getRecoveryReport().getSummary());
return r;
}
@Transactional
void persistEntities(HostEntity hostEntity) {
hostDAO.create(hostEntity);
if (!hostEntity.getClusterEntities().isEmpty()) {
for (ClusterEntity clusterEntity : hostEntity.getClusterEntities()) {
clusterEntity.getHostEntities().add(hostEntity);
clusterDAO.merge(clusterEntity);
}
}
}
@Override
@Transactional
public boolean addDesiredConfig(long clusterId, boolean selected, String user, Config config) {
if (null == user) {
throw new NullPointerException("User must be specified.");
}
HostConfigMapping exist = getDesiredConfigEntity(clusterId, config.getType());
if (null != exist && exist.getVersion().equals(config.getTag())) {
if (!selected) {
exist.setSelected(0);
hostConfigMappingDAO.merge(exist);
}
return false;
}
writeLock.lock();
HostEntity hostEntity = getHostEntity();
try {
// set all old mappings for this type to empty
for (HostConfigMapping e : hostConfigMappingDAO.findByType(clusterId,
hostEntity.getHostId(), config.getType())) {
e.setSelected(0);
hostConfigMappingDAO.merge(e);
}
HostConfigMapping hostConfigMapping = new HostConfigMappingImpl();
hostConfigMapping.setClusterId(clusterId);
hostConfigMapping.setCreateTimestamp(System.currentTimeMillis());
hostConfigMapping.setHostId(hostEntity.getHostId());
hostConfigMapping.setSelected(1);
hostConfigMapping.setUser(user);
hostConfigMapping.setType(config.getType());
hostConfigMapping.setVersion(config.getTag());
hostConfigMappingDAO.create(hostConfigMapping);
}
finally {
writeLock.unlock();
}
hostDAO.merge(hostEntity);
return true;
}
@Override
public Map<String, DesiredConfig> getDesiredConfigs(long clusterId) {
Map<String, DesiredConfig> map = new HashMap<>();
for (HostConfigMapping e : hostConfigMappingDAO.findSelected(
clusterId, getHostId())) {
DesiredConfig dc = new DesiredConfig();
dc.setTag(e.getVersion());
dc.setServiceName(e.getServiceName());
map.put(e.getType(), dc);
}
return map;
}
/**
* {@inheritDoc}
*/
@Override
public Map<String, HostConfig> getDesiredHostConfigs(Cluster cluster,
Map<String, DesiredConfig> clusterDesiredConfigs) throws AmbariException {
Map<String, HostConfig> hostConfigMap = new HashMap<>();
if( null == cluster ){
clusterDesiredConfigs = new HashMap<>();
}
// per method contract, fetch if not supplied
if (null == clusterDesiredConfigs) {
clusterDesiredConfigs = cluster.getDesiredConfigs();
}
if (clusterDesiredConfigs != null) {
for (Map.Entry<String, DesiredConfig> desiredConfigEntry
: clusterDesiredConfigs.entrySet()) {
HostConfig hostConfig = new HostConfig();
hostConfig.setDefaultVersionTag(desiredConfigEntry.getValue().getTag());
hostConfigMap.put(desiredConfigEntry.getKey(), hostConfig);
}
}
Map<Long, ConfigGroup> configGroups = (cluster == null) ? new HashMap<Long, ConfigGroup>() : cluster.getConfigGroupsByHostname(getHostName());
if (configGroups != null && !configGroups.isEmpty()) {
for (ConfigGroup configGroup : configGroups.values()) {
for (Map.Entry<String, Config> configEntry : configGroup
.getConfigurations().entrySet()) {
String configType = configEntry.getKey();
// HostConfig config holds configType -> versionTag, per config group
HostConfig hostConfig = hostConfigMap.get(configType);
if (hostConfig == null) {
hostConfig = new HostConfig();
hostConfigMap.put(configType, hostConfig);
if (cluster != null) {
Config conf = cluster.getDesiredConfigByType(configType);
if(conf == null) {
LOG.error("Config inconsistency exists:"+
" unknown configType="+configType);
} else {
hostConfig.setDefaultVersionTag(conf.getTag());
}
}
}
Config config = configEntry.getValue();
hostConfig.getConfigGroupOverrides().put(configGroup.getId(),
config.getTag());
}
}
}
return hostConfigMap;
}
private HostConfigMapping getDesiredConfigEntity(long clusterId, String type) {
return hostConfigMappingDAO.findSelectedByType(clusterId, getHostId(), type);
}
private ConcurrentMap<Long, MaintenanceState> ensureMaintMap(HostStateEntity hostStateEntity) {
if (null == hostStateEntity || null == hostStateEntity.getMaintenanceState()) {
return new ConcurrentHashMap<>();
}
String entity = hostStateEntity.getMaintenanceState();
final ConcurrentMap<Long, MaintenanceState> map;
try {
Map<Long, MaintenanceState> gsonMap = gson.fromJson(entity, maintMapType);
map = new ConcurrentHashMap<>(gsonMap);
} catch (Exception e) {
return new ConcurrentHashMap<>();
}
return map;
}
@Override
public void setMaintenanceState(long clusterId, MaintenanceState state) {
maintMap.put(clusterId, state);
String json = gson.toJson(maintMap, maintMapType);
HostStateEntity hostStateEntity = getHostStateEntity();
if (hostStateEntity != null) {
hostStateEntity.setMaintenanceState(json);
hostStateDAO.merge(hostStateEntity);
// broadcast the maintenance mode change
MaintenanceModeEvent event = new MaintenanceModeEvent(state, clusterId, this);
eventPublisher.publish(event);
}
}
@Override
public MaintenanceState getMaintenanceState(long clusterId) {
if (!maintMap.containsKey(clusterId)) {
maintMap.put(clusterId, MaintenanceState.OFF);
}
return maintMap.get(clusterId);
}
/**
* Get all of the HostVersionEntity objects for the host.
*
* @return all of the HostVersionEntity objects for the host
*/
@Override
public List<HostVersionEntity> getAllHostVersions() {
return hostVersionDAO.findByHost(getHostName());
}
// Get the cached host entity or load it fresh through the DAO.
@Override
public HostEntity getHostEntity() {
return hostDAO.findById(hostId);
}
// Get the cached host state entity or load it fresh through the DAO.
public HostStateEntity getHostStateEntity() {
return hostStateDAO.findByHostId(hostId);
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasComponentsAdvertisingVersions(StackId stackId) throws AmbariException {
HostEntity hostEntity = getHostEntity();
for (HostComponentStateEntity componentState : hostEntity.getHostComponentStateEntities()) {
ComponentInfo component = ambariMetaInfo.getComponent(stackId.getStackName(),
stackId.getStackVersion(), componentState.getServiceName(),
componentState.getComponentName());
if (component.isVersionAdvertised()) {
return true;
}
}
return false;
}
}