blob: 673f1a2becf0b6eeefe8459e6f1962f9a92e2764 [file] [log] [blame]
/**
* 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.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.persist.Transactional;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.agent.DiskInfo;
import org.apache.ambari.server.agent.AgentEnv;
import org.apache.ambari.server.agent.HostInfo;
import org.apache.ambari.server.controller.HostResponse;
import org.apache.ambari.server.orm.dao.ClusterDAO;
import org.apache.ambari.server.orm.dao.HostStateDAO;
import org.apache.ambari.server.orm.entities.ClusterEntity;
import org.apache.ambari.server.orm.entities.HostStateEntity;
import org.apache.ambari.server.state.*;
import org.apache.ambari.server.state.HostHealthStatus.HealthStatus;
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.orm.dao.HostDAO;
import org.apache.ambari.server.orm.entities.HostEntity;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class HostImpl implements Host {
private static final Log LOG = LogFactory.getLog(HostImpl.class);
private final Gson gson;
private static final Type diskInfoType =
new TypeToken<List<DiskInfo>>() {}.getType();
private static final Type hostAttributesType =
new TypeToken<Map<String, String>>() {}.getType();
ReadWriteLock rwLock;
private final Lock readLock;
private final Lock writeLock;
private HostEntity hostEntity;
private HostStateEntity hostStateEntity;
private Injector injector;
private HostDAO hostDAO;
private HostStateDAO hostStateDAO;
private ClusterDAO clusterDAO;
private Clusters clusters;
private long lastHeartbeatTime = 0L;
private AgentEnv lastAgentEnv = null;
private boolean persisted = false;
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 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();
private final StateMachine<HostState, HostEventType, HostEvent> stateMachine;
@Inject
public HostImpl(@Assisted HostEntity hostEntity,
@Assisted boolean persisted, Injector injector) {
this.stateMachine = stateMachineFactory.make(this);
rwLock = new ReentrantReadWriteLock();
this.readLock = rwLock.readLock();
this.writeLock = rwLock.writeLock();
this.hostEntity = hostEntity;
this.injector = injector;
this.persisted = persisted;
this.hostDAO = injector.getInstance(HostDAO.class);
this.hostStateDAO = injector.getInstance(HostStateDAO.class);
this.gson = injector.getInstance(Gson.class);
this.clusterDAO = injector.getInstance(ClusterDAO.class);
this.clusters = injector.getInstance(Clusters.class);
hostStateEntity = hostEntity.getHostStateEntity();
if (hostStateEntity == null) {
hostStateEntity = new HostStateEntity();
hostStateEntity.setHostEntity(hostEntity);
hostEntity.setHostStateEntity(hostStateEntity);
setHealthStatus(new HostHealthStatus(HealthStatus.UNKNOWN, ""));
if (persisted) {
persist();
}
} else {
this.stateMachine.setCurrentState(hostStateEntity.getCurrentState());
}
}
// //TODO delete
// public HostImpl(String hostname) {
// this.stateMachine = stateMachineFactory.make(this);
// ReadWriteLock rwLock = new ReentrantReadWriteLock();
// this.readLock = rwLock.readLock();
// this.writeLock = rwLock.writeLock();
// setHostName(hostname);
// setHealthStatus(new HostHealthStatus(HealthStatus.UNKNOWN, ""));
// }
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.persist();
}
}
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());
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()));
}
}
@Override
public void importHostInfo(HostInfo hostInfo) {
try {
writeLock.lock();
if (hostInfo.getIPAddress() != null
&& !hostInfo.getIPAddress().isEmpty()) {
setIPv4(hostInfo.getIPAddress());
setIPv6(hostInfo.getIPAddress());
}
setCpuCount(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
this.setAgentVersion(new AgentVersion(
hostInfo.getAgentUserId()));
Map<String, String> attrs = new HashMap<String, String>();
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());
}
setHostAttributes(attrs);
saveIfPersisted();
}
finally {
writeLock.unlock();
}
}
/**
* @param hostInfo
*/
@Override
public void setLastAgentEnv(AgentEnv env) {
lastAgentEnv = env;
}
@Override
public AgentEnv getLastAgentEnv() {
return lastAgentEnv;
}
@Override
public HostState getState() {
try {
readLock.lock();
return stateMachine.getCurrentState();
}
finally {
readLock.unlock();
}
}
@Override
public void setState(HostState state) {
try {
writeLock.lock();
stateMachine.setCurrentState(state);
hostStateEntity.setCurrentState(state);
hostStateEntity.setTimeInState(System.currentTimeMillis());
saveIfPersisted();
}
finally {
writeLock.unlock();
}
}
@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=" + this.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=" + this.getHostName()
+ ", oldState=" + oldState
+ ", currentState=" + getState()
+ ", eventType=" + event.getType().name()
+ ", event=" + event);
}
}
}
@Override
public String getHostName() {
try {
readLock.lock();
return hostEntity.getHostName();
} finally {
readLock.unlock();
}
}
@Override
public void setHostName(String hostName) {
try {
writeLock.lock();
if (!isPersisted()) {
hostEntity.setHostName(hostName);
} else {
throw new UnsupportedOperationException("PK of persisted entity cannot be modified");
}
} finally {
writeLock.unlock();
}
}
@Override
public void setPublicHostName(String hostName) {
try {
writeLock.lock();
hostEntity.setPublicHostName(hostName);
saveIfPersisted();
}
finally {
writeLock.unlock();
}
}
@Override
public String getPublicHostName() {
try {
readLock.lock();
return hostEntity.getPublicHostName();
}
finally {
readLock.unlock();
}
}
@Override
public String getIPv4() {
try {
readLock.lock();
return hostEntity.getIpv4();
} finally {
readLock.unlock();
}
}
@Override
public void setIPv4(String ip) {
try {
writeLock.lock();
hostEntity.setIpv4(ip);
saveIfPersisted();
} finally {
writeLock.unlock();
}
}
@Override
public String getIPv6() {
try {
readLock.lock();
return hostEntity.getIpv6();
} finally {
readLock.unlock();
}
}
@Override
public void setIPv6(String ip) {
try {
writeLock.lock();
hostEntity.setIpv6(ip);
saveIfPersisted();
} finally {
writeLock.unlock();
}
}
@Override
public int getCpuCount() {
try {
readLock.lock();
return hostEntity.getCpuCount();
} finally {
readLock.unlock();
}
}
@Override
public void setCpuCount(int cpuCount) {
try {
writeLock.lock();
hostEntity.setCpuCount(cpuCount);
saveIfPersisted();
} finally {
writeLock.unlock();
}
}
@Override
public long getTotalMemBytes() {
try {
readLock.lock();
return hostEntity.getTotalMem();
} finally {
readLock.unlock();
}
}
@Override
public void setTotalMemBytes(long totalMemBytes) {
try {
writeLock.lock();
hostEntity.setTotalMem(totalMemBytes);
saveIfPersisted();
} finally {
writeLock.unlock();
}
}
@Override
public long getAvailableMemBytes() {
try {
readLock.lock();
return hostStateEntity.getAvailableMem();
}
finally {
readLock.unlock();
}
}
@Override
public void setAvailableMemBytes(long availableMemBytes) {
try {
writeLock.lock();
hostStateEntity.setAvailableMem(availableMemBytes);
saveIfPersisted();
}
finally {
writeLock.unlock();
}
}
@Override
public String getOsArch() {
try {
readLock.lock();
return hostEntity.getOsArch();
} finally {
readLock.unlock();
}
}
@Override
public void setOsArch(String osArch) {
try {
writeLock.lock();
hostEntity.setOsArch(osArch);
saveIfPersisted();
} finally {
writeLock.unlock();
}
}
@Override
public String getOsInfo() {
try {
readLock.lock();
return hostEntity.getOsInfo();
} finally {
readLock.unlock();
}
}
@Override
public void setOsInfo(String osInfo) {
try {
writeLock.lock();
hostEntity.setOsInfo(osInfo);
saveIfPersisted();
} finally {
writeLock.unlock();
}
}
@Override
public String getOsType() {
try {
readLock.lock();
return hostEntity.getOsType();
} finally {
readLock.unlock();
}
}
@Override
public void setOsType(String osType) {
try {
writeLock.lock();
hostEntity.setOsType(osType);
saveIfPersisted();
} finally {
writeLock.unlock();
}
}
@Override
public List<DiskInfo> getDisksInfo() {
try {
readLock.lock();
return gson.<List<DiskInfo>>fromJson(
hostEntity.getDisksInfo(), diskInfoType);
} finally {
readLock.unlock();
}
}
@Override
public void setDisksInfo(List<DiskInfo> disksInfo) {
try {
writeLock.lock();
hostEntity.setDisksInfo(gson.toJson(disksInfo, diskInfoType));
saveIfPersisted();
} finally {
writeLock.unlock();
}
}
@Override
public HostHealthStatus getHealthStatus() {
try {
readLock.lock();
return gson.fromJson(hostStateEntity.getHealthStatus(),
HostHealthStatus.class);
} finally {
readLock.unlock();
}
}
@Override
public void setHealthStatus(HostHealthStatus healthStatus) {
try {
writeLock.lock();
hostStateEntity.setHealthStatus(gson.toJson(healthStatus));
saveIfPersisted();
} finally {
writeLock.unlock();
}
}
@Override
public Map<String, String> getHostAttributes() {
try {
readLock.lock();
return gson.<Map<String, String>>fromJson(hostEntity.getHostAttributes(),
hostAttributesType);
} finally {
readLock.unlock();
}
}
@Override
public void setHostAttributes(Map<String, String> hostAttributes) {
try {
writeLock.lock();
Map<String, String> hostAttrs = gson.<Map<String, String>>
fromJson(hostEntity.getHostAttributes(), hostAttributesType);
if (hostAttrs == null) {
hostAttrs = new HashMap<String, String>();
}
hostAttrs.putAll(hostAttributes);
hostEntity.setHostAttributes(gson.toJson(hostAttrs,
hostAttributesType));
saveIfPersisted();
} finally {
writeLock.unlock();
}
}
@Override
public String getRackInfo() {
try {
readLock.lock();
return hostEntity.getRackInfo();
} finally {
readLock.unlock();
}
}
@Override
public void setRackInfo(String rackInfo) {
try {
writeLock.lock();
hostEntity.setRackInfo(rackInfo);
saveIfPersisted();
} finally {
writeLock.unlock();
}
}
@Override
public long getLastRegistrationTime() {
try {
readLock.lock();
return hostEntity.getLastRegistrationTime();
} finally {
readLock.unlock();
}
}
@Override
public void setLastRegistrationTime(long lastRegistrationTime) {
try {
writeLock.lock();
this.hostEntity.setLastRegistrationTime(lastRegistrationTime);
saveIfPersisted();
} finally {
writeLock.unlock();
}
}
@Override
public long getLastHeartbeatTime() {
try {
readLock.lock();
return lastHeartbeatTime;
}
finally {
readLock.unlock();
}
}
@Override
public void setLastHeartbeatTime(long lastHeartbeatTime) {
try {
writeLock.lock();
this.lastHeartbeatTime = lastHeartbeatTime;
}
finally {
writeLock.unlock();
}
}
@Override
public AgentVersion getAgentVersion() {
try {
readLock.lock();
return gson.fromJson(hostStateEntity.getAgentVersion(),
AgentVersion.class);
}
finally {
readLock.unlock();
}
}
@Override
public void setAgentVersion(AgentVersion agentVersion) {
try {
writeLock.lock();
hostStateEntity.setAgentVersion(gson.toJson(agentVersion));
saveIfPersisted();
}
finally {
writeLock.unlock();
}
}
@Override
public long getTimeInState() {
return hostStateEntity.getTimeInState();
}
@Override
public void setTimeInState(long timeInState) {
try {
writeLock.lock();
hostStateEntity.setTimeInState(timeInState);
saveIfPersisted();
}
finally {
writeLock.unlock();
}
}
@Override
public HostResponse convertToResponse() {
try {
readLock.lock();
HostResponse r = new HostResponse(getHostName());
r.setAgentVersion(getAgentVersion());
r.setAvailableMemBytes(getAvailableMemBytes());
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());
return r;
}
finally {
readLock.unlock();
}
}
/**
* Shows if Host is persisted to database
*
* @return true if persisted
*/
@Override
public boolean isPersisted() {
try {
readLock.lock();
return persisted;
} finally {
readLock.unlock();
}
}
/**
* Save host to database and make all changes to be saved afterwards
*/
@Override
public void persist() {
writeLock.lock();
try {
if (!persisted) {
persistEntities();
refresh();
for (ClusterEntity clusterEntity : hostEntity.getClusterEntities()) {
try {
clusters.getClusterById(clusterEntity.getClusterId()).refresh();
} catch (AmbariException e) {
LOG.error(e);
throw new RuntimeException("Cluster '" + clusterEntity.getClusterId() + "' was removed", e);
}
}
persisted = true;
} else {
saveIfPersisted();
}
} finally {
writeLock.unlock();
}
}
@Transactional
void persistEntities() {
hostDAO.create(hostEntity);
hostStateDAO.create(hostStateEntity);
if (!hostEntity.getClusterEntities().isEmpty()) {
for (ClusterEntity clusterEntity : hostEntity.getClusterEntities()) {
clusterEntity.getHostEntities().add(hostEntity);
clusterDAO.merge(clusterEntity);
}
}
}
@Override
@Transactional
public void refresh() {
writeLock.lock();
try {
if (isPersisted()) {
hostEntity = hostDAO.findByName(hostEntity.getHostName());
hostStateEntity = hostEntity.getHostStateEntity();
hostDAO.refresh(hostEntity);
hostStateDAO.refresh(hostStateEntity);
}
} finally {
writeLock.unlock();
}
}
@Transactional
void saveIfPersisted() {
if (isPersisted()) {
hostDAO.merge(hostEntity);
hostStateDAO.merge(hostStateEntity);
}
}
}