/*
* Copyright 2016 ThoughtWorks, Inc.
*
* Licensed 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 com.thoughtworks.go.server.service;
import com.google.gson.annotations.Expose;
import com.thoughtworks.go.config.AgentConfig;
import com.thoughtworks.go.domain.AgentRuntimeStatus;
import com.thoughtworks.go.domain.AgentStatus;
import com.thoughtworks.go.domain.DiskSpace;
import com.thoughtworks.go.remote.AgentIdentifier;
import com.thoughtworks.go.util.SystemEnvironment;
import com.thoughtworks.go.util.SystemUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.log4j.Logger;
import java.io.File;
import java.io.Serializable;
import static java.lang.String.format;
public class AgentRuntimeInfo implements Serializable {
private static Logger LOGGER = Logger.getLogger(AgentRuntimeInfo.class);
@Expose
private AgentIdentifier identifier;
@Expose
private volatile AgentRuntimeStatus runtimeStatus;
@Expose
private volatile AgentBuildingInfo buildingInfo;
@Expose
private volatile String location;
@Expose
private volatile Long usableSpace;
@Expose
private volatile String operatingSystemName;
@Expose
private volatile String cookie;
@Expose
private volatile boolean supportsBuildCommandProtocol;
public AgentRuntimeInfo(AgentIdentifier identifier, AgentRuntimeStatus runtimeStatus, String location, String cookie, boolean supportsBuildCommandProtocol) {
this.identifier = identifier;
this.runtimeStatus = runtimeStatus;
this.supportsBuildCommandProtocol = supportsBuildCommandProtocol;
this.buildingInfo = AgentBuildingInfo.NOT_BUILDING;
this.location = location;
this.cookie = cookie;
}
public static AgentRuntimeInfo fromAgent(AgentIdentifier identifier, AgentRuntimeStatus runtimeStatus, String currentWorkingDirectory, boolean supportsBuildCommandProtocol) {
return new AgentRuntimeInfo(identifier, runtimeStatus, currentWorkingDirectory, null, supportsBuildCommandProtocol).refreshOperatingSystem().refreshUsableSpace();
}
public static AgentRuntimeInfo fromServer(AgentConfig agentConfig, boolean registeredAlready, String location,
Long usablespace, String operatingSystem, boolean supportsBuildCommandProtocol) {
if (StringUtils.isEmpty(location)) {
throw new RuntimeException("Agent should not register without installation path.");
}
AgentStatus status = AgentStatus.Pending;
if (SystemUtil.isLocalIpAddress(agentConfig.getIpAddress()) || registeredAlready) {
status = AgentStatus.Idle;
}
AgentRuntimeInfo agentRuntimeInfo = new AgentRuntimeInfo(agentConfig.getAgentIdentifier(), status.getRuntimeStatus(), location, null, supportsBuildCommandProtocol);
agentRuntimeInfo.setUsableSpace(usablespace);
agentRuntimeInfo.operatingSystemName = operatingSystem;
return agentRuntimeInfo;
}
public static AgentRuntimeInfo initialState(AgentConfig agentConfig) {
AgentRuntimeInfo agentRuntimeInfo = new AgentRuntimeInfo(agentConfig.getAgentIdentifier(), AgentStatus.fromRuntime(AgentRuntimeStatus.Missing).getRuntimeStatus(), "", null, false);
if (agentConfig.isElastic()) {
agentRuntimeInfo = ElasticAgentRuntimeInfo.fromServer(agentRuntimeInfo, agentConfig.getElasticAgentId(), agentConfig.getElasticPluginId());
}
return agentRuntimeInfo;
}
public void busy(AgentBuildingInfo agentBuildingInfo) {
this.buildingInfo = agentBuildingInfo;
this.runtimeStatus = AgentRuntimeStatus.Building;
}
public void cancel() {
this.runtimeStatus = AgentRuntimeStatus.Cancelled;
}
public void idle() {
this.runtimeStatus = AgentRuntimeStatus.Idle;
this.buildingInfo = AgentBuildingInfo.NOT_BUILDING;
}
public AgentRuntimeStatus getRuntimeStatus() {
return runtimeStatus;
}
public AgentBuildingInfo getBuildingInfo() {
return buildingInfo;
}
public boolean isCancelled() {
return runtimeStatus == AgentRuntimeStatus.Cancelled;
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AgentRuntimeInfo that = (AgentRuntimeInfo) o;
if (buildingInfo != null ? !buildingInfo.equals(that.buildingInfo) : that.buildingInfo != null) {
return false;
}
if (identifier != null ? !identifier.equals(that.identifier) : that.identifier != null) {
return false;
}
if (location != null ? !location.equals(that.location) : that.location != null) {
return false;
}
if (operatingSystemName != null ? !operatingSystemName.equals(that.operatingSystemName) : that.operatingSystemName != null) {
return false;
}
if (hasCookie() ? !cookie.equals(that.cookie) : that.hasCookie()) {
return false;
}
if (runtimeStatus != that.runtimeStatus) {
return false;
}
if (supportsBuildCommandProtocol != that.supportsBuildCommandProtocol) {
return false;
}
return true;
}
public int hashCode() {
int result;
result = (identifier != null ? identifier.hashCode() : 0);
result = 31 * result + (runtimeStatus != null ? runtimeStatus.hashCode() : 0);
result = 31 * result + (buildingInfo != null ? buildingInfo.hashCode() : 0);
result = 31 * result + (location != null ? location.hashCode() : 0);
result = 31 * result + (hasCookie() ? cookie.hashCode() : 0);
result = 31 * result + (int) (usableSpace != null ? usableSpace ^ (usableSpace >>> 32) : 0);
result = 31 * result + (supportsBuildCommandProtocol ? 1 : 0);
return result;
}
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
public String getUUId() {
return identifier.getUuid();
}
public AgentConfig agent() {
return new AgentConfig(getUUId(), identifier.getHostName(), identifier.getIpAddress());
}
public String getIpAdress() {
return identifier.getIpAddress();
}
public String getHostName() {
return identifier.getHostName();
}
public AgentIdentifier getIdentifier() {
return identifier;
}
public String getLocation() {
return location;
}
public String getCookie() {
return cookie;
}
public void setStatus(AgentStatus status) {
this.runtimeStatus = status.getRuntimeStatus();
}
public void setBuildingInfo(AgentBuildingInfo buildingInfo) {
this.buildingInfo = buildingInfo;
}
public void setLocation(String location) {
this.location = location;
}
public AgentRuntimeInfo refreshOperatingSystem() {
setOperatingSystem(new SystemEnvironment().getOperatingSystemCompleteName());
return this;
}
public AgentRuntimeInfo refreshUsableSpace() {
setUsableSpace(usableSpace(location));
return this;
}
public static long usableSpace(String currentWorkingDir) {
File file = new File(currentWorkingDir, "pipelines");
if (!file.exists()) {
LOGGER.warn(
"the [" + file.getAbsolutePath() + "] should be created when agent starts up, "
+ "but it seems missing at the moment. "
+ "Cruise should be able to automatically create it later");
}
return file.getUsableSpace();
}
public Long getUsableSpace() {
return usableSpace;
}
public void setUsableSpace(Long usableSpace) {
this.usableSpace = usableSpace;
}
public void clearBuildingInfo() {
this.buildingInfo = AgentBuildingInfo.NOT_BUILDING;
}
public boolean isLowDiskSpace(long limit) {
if (usableSpace == null) {
return false;
}
return usableSpace < limit;
}
public String agentInfoDebugString() {
return format("Agent [%s, %s, %s, %s]", getHostName(), getIpAdress(), getUUId(), cookie);
}
public String agentInfoForDisplay() {
return format("Agent located at [%s, %s, %s]", getHostName(), getIpAdress(), getLocation());
}
public String getOperatingSystem() {
return operatingSystemName;
}
public void setOperatingSystem(String operatingSystem) {
this.operatingSystemName = operatingSystem;
}
public boolean hasDuplicateCookie(String cookie) {
return hasCookie() && cookie != null && !this.cookie.equals(cookie);
}
public boolean hasCookie() {
return this.cookie != null;
}
public void setCookie(String cookie) {
this.cookie = cookie;
}
public void setRuntimeStatus(AgentRuntimeStatus runtimeStatus, AgentRuntimeStatus.ChangeListener changeListener) {
if (this.runtimeStatus != runtimeStatus) {
if (changeListener != null) {
changeListener.statusUpdateRequested(this, runtimeStatus);
}
this.runtimeStatus = runtimeStatus;
}
}
public DiskSpace freeDiskSpace() {
Long space = usableSpace;
AgentRuntimeStatus status = runtimeStatus;
return (status == AgentRuntimeStatus.Missing || status == AgentRuntimeStatus.LostContact || space == null) ? DiskSpace.unknownDiskSpace() : new DiskSpace(space);
}
public void updateSelf(AgentRuntimeInfo newRuntimeInfo) {
this.buildingInfo = newRuntimeInfo.getBuildingInfo();
if (newRuntimeInfo.isCancelled()) {
this.setRuntimeStatus(AgentRuntimeStatus.Cancelled, null);
}
this.location = newRuntimeInfo.getLocation();
this.usableSpace = newRuntimeInfo.getUsableSpace();
this.operatingSystemName = newRuntimeInfo.getOperatingSystem();
this.supportsBuildCommandProtocol = newRuntimeInfo.getSupportsBuildCommandProtocol();
}
public boolean getSupportsBuildCommandProtocol() {
return supportsBuildCommandProtocol;
}
public void setSupportsBuildCommandProtocol(boolean b) {
this.supportsBuildCommandProtocol = b;
}
public boolean isElastic() {
return false;
}
}