/*
* Copyright 2017 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.agent;
import com.thoughtworks.go.agent.service.AgentUpgradeService;
import com.thoughtworks.go.agent.service.SslInfrastructureService;
import com.thoughtworks.go.config.AgentAutoRegistrationProperties;
import com.thoughtworks.go.config.AgentRegistry;
import com.thoughtworks.go.domain.AgentRuntimeStatus;
import com.thoughtworks.go.domain.AgentStatus;
import com.thoughtworks.go.plugin.infra.PluginManager;
import com.thoughtworks.go.plugin.infra.PluginManagerReference;
import com.thoughtworks.go.remote.AgentIdentifier;
import com.thoughtworks.go.server.service.AgentRuntimeInfo;
import com.thoughtworks.go.server.service.ElasticAgentRuntimeInfo;
import com.thoughtworks.go.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import static com.thoughtworks.go.util.SystemUtil.currentWorkingDirectory;
public abstract class AgentController {
private static final Logger LOG = LoggerFactory.getLogger(AgentController.class);
private AgentRuntimeInfo agentRuntimeInfo;
private AgentAutoRegistrationProperties agentAutoRegistrationProperties;
private AgentIdentifier identifier;
private SslInfrastructureService sslInfrastructureService;
private SystemEnvironment systemEnvironment;
private AgentRegistry agentRegistry;
private SubprocessLogger subprocessLogger;
private AgentUpgradeService agentUpgradeService;
private final String hostName;
private final String ipAddress;
public AgentController(SslInfrastructureService sslInfrastructureService,
SystemEnvironment systemEnvironment,
AgentRegistry agentRegistry,
PluginManager pluginManager,
SubprocessLogger subprocessLogger, AgentUpgradeService agentUpgradeService) {
this.sslInfrastructureService = sslInfrastructureService;
this.systemEnvironment = systemEnvironment;
this.agentRegistry = agentRegistry;
this.subprocessLogger = subprocessLogger;
this.agentUpgradeService = agentUpgradeService;
PluginManagerReference.reference().setPluginManager(pluginManager);
hostName = SystemUtil.getLocalhostNameOrRandomNameIfNotFound();
ipAddress = SystemUtil.getClientIp(systemEnvironment.getServiceUrl());
}
public abstract void ping();
public abstract void execute();
public final void loop() {
try {
LOG.debug("[Agent Loop] Trying to retrieve work.");
agentUpgradeService.checkForUpgrade();
sslInfrastructureService.registerIfNecessary(getAgentAutoRegistrationProperties());
work();
LOG.debug("[Agent Loop] Successfully retrieved work.");
} catch (Exception e) {
if (isCausedBySecurity(e)) {
handleSecurityException(e);
} else {
LOG.error("[Agent Loop] Error occurred during loop: ", e);
}
}
}
private void handleSecurityException(Exception e) {
sslInfrastructureService.invalidateAgentCertificate();
LOG.error("There has been a problem with one of Go's SSL certificates." +
" This can be caused by a man-in-the-middle attack, or by pointing the agent to a new server, or by" +
" deleting and re-installing Go Server. Go will ask for a new certificate. If this" +
" fails to solve the problem, try deleting config/trust.jks in Go Agent's home directory.",
e);
}
protected abstract void work() throws Exception;
protected AgentRegistry getAgentRegistry() {
return agentRegistry;
}
protected AgentAutoRegistrationProperties getAgentAutoRegistrationProperties() {
return agentAutoRegistrationProperties;
}
protected SystemEnvironment getSystemEnvironment() {
return systemEnvironment;
}
protected AgentIdentifier agentIdentifier() {
return new AgentIdentifier(hostName, ipAddress, agentRegistry.uuid());
}
protected AgentRuntimeInfo getAgentRuntimeInfo() {
return agentRuntimeInfo;
}
boolean isCausedBySecurity(Throwable e) {
if (e == null) {
return false;
}
return (e instanceof GeneralSecurityException) || isCausedBySecurity(e.getCause());
}
// Executed when Spring initializes this bean
void init() throws IOException {
initPipelinesFolder();
initSslInfratructure();
initAgentIdentifier();
initRuntimeInfo();
initSubProcessLogger();
}
private void initSubProcessLogger() {
subprocessLogger.registerAsExitHook("Following processes were alive at shutdown: ");
}
private void initSslInfratructure() throws IOException {
sslInfrastructureService.createSslInfrastructure();
}
private void initAgentIdentifier() {
identifier = agentIdentifier();
}
private void initRuntimeInfo() {
Boolean buildCommandProtocolEnabled = systemEnvironment.isBuildCommandProtocolEnabled();
agentAutoRegistrationProperties = new AgentAutoRegistrationPropertiesImpl(new File("config", "autoregister.properties"));
if (agentAutoRegistrationProperties.isElastic()) {
agentRuntimeInfo = ElasticAgentRuntimeInfo.fromAgent(identifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), agentAutoRegistrationProperties.agentAutoRegisterElasticAgentId(), agentAutoRegistrationProperties.agentAutoRegisterElasticPluginId());
} else {
agentRuntimeInfo = AgentRuntimeInfo.fromAgent(identifier, AgentStatus.Idle.getRuntimeStatus(), currentWorkingDirectory(), buildCommandProtocolEnabled);
}
}
private void initPipelinesFolder() {
File pipelines = new File(currentWorkingDirectory(), "pipelines");
if (!pipelines.exists()) {
pipelines.mkdirs();
}
}
}