View
@@ -1,22 +1,23 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent.bootstrapper.osx;
import com.thoughtworks.go.agent.bootstrapper.AgentBootstrapper;
import com.thoughtworks.go.agent.common.AgentBootstrapperArgs;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -25,20 +26,18 @@
*/
public class MacBootstrapperThread extends Thread{
private static final Log LOG = LogFactory.getLog(MacBootstrapperThread.class);
private final String server;
private final int port;
private final AgentBootstrapperArgs bootstrapperArgs;
private AgentBootstrapper bootstrapper;
public MacBootstrapperThread(String server, int port) {
this.server = server;
this.port = port;
setName("MacBootstrapper"+getName() +" "+ server+ ":"+port);
public MacBootstrapperThread(AgentBootstrapperArgs bootstrapperArgs) {
this.bootstrapperArgs = bootstrapperArgs;
setName("MacBootstrapper"+getName() +" "+ this.bootstrapperArgs);
}
public void run() {
LOG.info("Launching Agent Bootstrapper for server " + server + ":" + port);
LOG.info("Launching Agent Bootstrapper for server " + bootstrapperArgs);
bootstrapper = new AgentBootstrapper();
bootstrapper.go(true, server, port);
bootstrapper.go(true, bootstrapperArgs);
}
public void stopLooping() {
View
@@ -1,88 +1,252 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent.bootstrapper.osx;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JTextField;
import javax.swing.JPanel;
import com.beust.jcommander.ParameterException;
import com.thoughtworks.go.agent.common.AgentBootstrapperArgs;
import com.thoughtworks.go.agent.common.CertificateFileValidator;
import com.thoughtworks.go.agent.common.ServerUrlValidator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
public class MacPreferencesPane extends JFrame {
private static final Log LOG = LogFactory.getLog(AgentMacWindow.class);
private JTextField serverTextField;
private String originalHost;
private FileBrowser fileBrowser;
private JButton okButton;
private AgentMacWindow agentMacWindow;
private SslModeComponent sslModeComponent;
public MacPreferencesPane(final AgentMacWindow agentMacWindow) {
super();
this.agentMacWindow = agentMacWindow;
BorderLayout border = new BorderLayout(10, 10);
getContentPane().setLayout(border);
createView();
sslModeComponent.noneModeRadioButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fileBrowser.setEnabled(!sslModeComponent.noneModeRadioButton.isSelected());
}
});
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent newEvent) {
try {
AgentBootstrapperArgs newArgs = new AgentBootstrapperArgs(
new URL(serverTextField.getText()),
fileBrowser.getFile(), sslModeComponent.getSslMode());
try {
new ServerUrlValidator().validate("The server url", newArgs.getServerUrl().toExternalForm());
} catch (ParameterException e) {
JOptionPane.showMessageDialog(getContentPane(), e.getMessage(), "Invalid server url", JOptionPane.ERROR_MESSAGE);
return;
}
if (newArgs.getRootCertFile() != null) {
try {
new CertificateFileValidator().validate("The server root certificate", newArgs.getRootCertFile().getPath());
} catch (ParameterException e) {
JOptionPane.showMessageDialog(getContentPane(), e.getMessage(), "Invalid server root certificate", JOptionPane.ERROR_MESSAGE);
return;
}
}
if (!newArgs.equals(agentMacWindow.getBootstrapperArgs())) {
agentMacWindow.setBootstrapperArgs(newArgs);
LOG.info("Updating preferences to " + newArgs);
} else {
LOG.info("Preferences are unchanged " + newArgs);
}
setVisible(false);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(getContentPane(), "The server url must be an HTTPS url and must begin with https://", "Invalid server url", JOptionPane.ERROR_MESSAGE);
}
}
});
getContentPane().setLayout(new BorderLayout(10, 10));
JLabel prefsText = new JLabel("Go Server Hostname or IP");
setSize(getPreferredSize());
setLocation(20, 30);
setResizable(false);
}
private void createView() {
JPanel controlsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 10));
serverTextField = new JTextField("");
serverTextField.setColumns(15);
serverTextField.selectAll();
JPanel textPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 10));
textPanel.add(prefsText);
JPanel textPanel = new JPanel(new GridLayout(4, 2, 0, 10));
textPanel.add(new JLabel("Go Server Hostname or IP"));
textPanel.add(serverTextField);
getContentPane().add(textPanel, BorderLayout.NORTH);
textPanel.add(new JLabel("SSL Mode"));
sslModeComponent = new SslModeComponent();
textPanel.add(sslModeComponent);
textPanel.add(new JLabel("Server root certificate"));
fileBrowser = new FileBrowser();
textPanel.add(fileBrowser);
controlsPanel.add(textPanel);
getContentPane().add(controlsPanel, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 10));
JButton okButton = new JButton("OK");
okButton = new JButton("OK");
buttonPanel.add(okButton);
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent newEvent) {
String newHost = serverTextField.getText();
if (!originalHost.equals(newHost)) {
LOG.info("Server changed to " + newHost);
agentMacWindow.setHost(newHost);
} else {
LOG.info("Server is still " + originalHost);
}
setVisible(false);
}
});
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
setSize(getPreferredSize());
setLocation(20, 40);
setResizable(false);
}
public void ask() {
this.serverTextField.setText(originalHost);
AgentBootstrapperArgs bootstrapperArgs = agentMacWindow.getBootstrapperArgs();
this.serverTextField.setText(bootstrapperArgs.getServerUrl().toString());
this.fileBrowser.setFile(bootstrapperArgs.getRootCertFile());
this.sslModeComponent.setSslMode(bootstrapperArgs.getSslMode());
serverTextField.selectAll();
serverTextField.grabFocus();
setVisible(true);
}
public void setOriginalHost(String originalHost) {
this.originalHost = originalHost;
private class FileBrowser extends JPanel {
private File file;
private final JTextField textField;
private final JButton browse;
FileBrowser() {
super();
setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
textField = new JTextField(15);
textField.setEnabled(false);
add(textField);
browse = new JButton("Browse");
add(browse);
browse.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser jFileChooser = new JFileChooser(file != null ? file.getParentFile() : null);
int returnVal = jFileChooser.showOpenDialog(FileBrowser.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
setFile(jFileChooser.getSelectedFile());
}
}
});
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
browse.setEnabled(enabled);
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
if (file != null) {
textField.setText(file.toString());
}
}
}
private class SslModeComponent extends JPanel {
private AgentBootstrapperArgs.SslMode sslVerificationMode;
private final JRadioButton fullModeRadioButton;
private final JRadioButton noneModeRadioButton;
private final JRadioButton noHostVerifyModeRadioButton;
SslModeComponent() {
super();
setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
fullModeRadioButton = new JRadioButton("Full Verification");
fullModeRadioButton.putClientProperty("SSL_MODE", AgentBootstrapperArgs.SslMode.FULL);
fullModeRadioButton.setToolTipText("Perform a complete SSL verification before connecting to the agent.");
noneModeRadioButton = new JRadioButton("No verification");
noneModeRadioButton.putClientProperty("SSL_MODE", AgentBootstrapperArgs.SslMode.NONE);
noneModeRadioButton.setToolTipText("Completely disable any SSL verification");
noHostVerifyModeRadioButton = new JRadioButton("Don't verify host");
noHostVerifyModeRadioButton.putClientProperty("SSL_MODE", AgentBootstrapperArgs.SslMode.NO_VERIFY_HOST);
noHostVerifyModeRadioButton.setToolTipText("Verify the server certificate, but not the hostname.");
ButtonGroup sslModeButtonGroup = new ButtonGroup();
ActionListener actionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JRadioButton b = (JRadioButton) e.getSource();
setSslMode((AgentBootstrapperArgs.SslMode) b.getClientProperty("SSL_MODE"));
}
};
for (JRadioButton button : Arrays.asList(fullModeRadioButton, noneModeRadioButton, noHostVerifyModeRadioButton)) {
sslModeButtonGroup.add(button);
add(button);
button.addActionListener(actionListener);
}
}
private void setSslMode(AgentBootstrapperArgs.SslMode sslVerificationMode) {
switch (sslVerificationMode) {
case FULL:
fullModeRadioButton.setSelected(true);
fileBrowser.setEnabled(true);
break;
case NONE:
noneModeRadioButton.setSelected(true);
fileBrowser.setEnabled(false);
break;
case NO_VERIFY_HOST:
noHostVerifyModeRadioButton.setSelected(true);
fileBrowser.setEnabled(true);
break;
}
this.sslVerificationMode = sslVerificationMode;
}
public AgentBootstrapperArgs.SslMode getSslMode() {
return sslVerificationMode;
}
}
}
View
@@ -1,28 +1,23 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent.bootstrapper;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import com.googlecode.junit.ext.checkers.OSChecker;
import com.thoughtworks.go.agent.common.AgentBootstrapperArgs;
import com.thoughtworks.go.agent.common.util.Downloader;
import com.thoughtworks.go.agent.testhelper.FakeBootstrapperServer;
import com.thoughtworks.go.util.FileUtil;
@@ -34,13 +29,12 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.hamcrest.core.Is.is;
import java.io.*;
import java.net.URL;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertThat;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.*;
@RunWith(FakeBootstrapperServer.class)
public class AgentBootstrapperFunctionalTest {
@@ -70,7 +64,7 @@ public void shouldCheckout_Bundled_agentLauncher() throws IOException {
}
@Test
public void shouldLoadAndBootstrapJarUsingAgentBootstrapCode_specifiedInAgentManifestFile() {
public void shouldLoadAndBootstrapJarUsingAgentBootstrapCode_specifiedInAgentManifestFile() throws Exception {
if (!OS_CHECKER.satisfy()) {
PrintStream err = System.err;
try {
@@ -79,11 +73,11 @@ public void shouldLoadAndBootstrapJarUsingAgentBootstrapCode_specifiedInAgentMan
File agentJar = new File("agent.jar");
agentJar.delete();
new AgentBootstrapper(){
@Override void jvmExit(int returnValue) {
}
}.go(false, "localhost", 9090);
@Override void jvmExit(int returnValue) {
}
}.go(false, new AgentBootstrapperArgs(new URL("http://" + "localhost" + ":" + 9090 + "/go"), null, AgentBootstrapperArgs.SslMode.NONE));
agentJar.delete();
assertThat(new String(os.toByteArray()), is("Hello World Fellas!"));
assertThat(new String(os.toByteArray()), containsString("Hello World Fellas!"));
} finally {
System.setErr(err);
}
@@ -96,9 +90,9 @@ public void shouldDownloadJarIfItDoesNotExist() throws Exception {
File agentJar = new File("agent.jar");
agentJar.delete();
new AgentBootstrapper(){
@Override void jvmExit(int returnValue) {
}
}.go(false, "localhost", 9090);
@Override void jvmExit(int returnValue) {
}
}.go(false, new AgentBootstrapperArgs(new URL("http://" + "localhost" + ":" + 9090 + "/go"), null, AgentBootstrapperArgs.SslMode.NONE));
assertTrue("No agent downloaded", agentJar.exists());
agentJar.delete();
}
@@ -112,9 +106,9 @@ public void shouldDownloadJarIfTheCurrentOneIsWrong() throws Exception {
createRandomFile(agentJar);
long original = agentJar.length();
new AgentBootstrapper(){
@Override void jvmExit(int returnValue) {
}
}.go(false, "localhost", 9090);
@Override void jvmExit(int returnValue) {
}
}.go(false, new AgentBootstrapperArgs(new URL("http://" + "localhost" + ":" + 9090 + "/go"), null, AgentBootstrapperArgs.SslMode.NONE));
assertThat(agentJar.length(), not(original));
agentJar.delete();
}
@@ -125,9 +119,9 @@ public void shouldDieNicelyIfWrongUrl() {
new File("agent.jar").delete();
try {
new AgentBootstrapper(){
@Override void jvmExit(int returnValue) {
}
}.go(false, "IShouldNotResolveAtAll", 9090);
@Override void jvmExit(int returnValue) {
}
}.go(false, new AgentBootstrapperArgs(new URL("http://" + "IShouldNotResolveAtAll" + ":" + 9090 + "/go"), null, AgentBootstrapperArgs.SslMode.NONE));
fail("Shouldn't work if wrong URL provided");
} catch (Exception e) {
assertThat(e.getMessage(), containsString("Please check the URL"));
View
@@ -1,34 +1,36 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent.bootstrapper;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Semaphore;
import com.thoughtworks.cruise.agent.common.launcher.AgentLaunchDescriptor;
import com.thoughtworks.cruise.agent.common.launcher.AgentLauncher;
import com.thoughtworks.go.agent.common.AgentBootstrapperArgs;
import com.thoughtworks.go.util.ReflectionUtil;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.fail;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Semaphore;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
@@ -40,16 +42,6 @@ public void setUp() throws Exception {
System.setProperty(AgentBootstrapper.WAIT_TIME_BEFORE_RELAUNCH_IN_MS, "0");
}
@Test
public void shouldDieIfNoArguments() {
try {
AgentBootstrapper.main(null);
fail("We need an argument -- where is the server?");
} catch (Exception e) {
// Yeah!!!!
}
}
@Test
public void shouldNotDieWhenCreationOfLauncherRaisesException() throws InterruptedException {
final Semaphore waitForLauncherCreation = new Semaphore(1);
@@ -98,7 +90,7 @@ public void run() {
});
stopLoopThd.start();
try {
spyBootstrapper.go(true, "ghost-name", 3518);
spyBootstrapper.go(true, new AgentBootstrapperArgs(new URL("http://" + "ghost-name" + ":" + 3518 + "/go"), null, AgentBootstrapperArgs.SslMode.NONE));
stopLoopThd.join();
} catch (Exception e) {
fail("should not have propagated exception thrown while creating launcher");
@@ -129,7 +121,7 @@ public void destroy() {
final AgentBootstrapper spyBootstrapper = stubJVMExit(bootstrapper);
try {
spyBootstrapper.go(true, "ghost-name", 3518);
spyBootstrapper.go(true, new AgentBootstrapperArgs(new URL("http://" + "ghost-name" + ":" + 3518 + "/go"), null, AgentBootstrapperArgs.SslMode.NONE));
} catch (Exception e) {
fail("should not have propagated exception thrown while invoking the launcher");
}
@@ -180,15 +172,15 @@ public void run() {
});
stopLoopThd.start();
try {
spyBootstrapper.go(true, "ghost-name", 3518);
spyBootstrapper.go(true, new AgentBootstrapperArgs(new URL("http://" + "ghost-name" + ":" + 3518 + "/go"), null, AgentBootstrapperArgs.SslMode.NONE));
stopLoopThd.join();
} catch (Exception e) {
fail("should not have propagated exception thrown while invoking the launcher");
}
}
@Test
public void shouldRetainStateAcrossLauncherInvocations() {
public void shouldRetainStateAcrossLauncherInvocations() throws Exception {
final Map expectedContext = new HashMap();
AgentBootstrapper agentBootstrapper = new AgentBootstrapper() {
@@ -227,7 +219,7 @@ public void destroy() {
}
};
AgentBootstrapper spy = stubJVMExit(agentBootstrapper);
spy.go(true, "localhost", 80);
spy.go(true, new AgentBootstrapperArgs(new URL("http://" + "localhost" + ":" + 80 + "/go"), null, AgentBootstrapperArgs.SslMode.NONE));
}
private AgentBootstrapper stubJVMExit(AgentBootstrapper bootstrapper) {
View
@@ -1,46 +1,39 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent.bootstrapper;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.thoughtworks.cruise.agent.common.launcher.AgentLaunchDescriptorKeys;
import com.thoughtworks.go.agent.common.AgentBootstrapperArgs;
import org.junit.Test;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.net.URL;
import java.util.Map;
import static org.junit.Assert.assertEquals;
public class DefaultAgentLaunchDescriptorImplTest {
@Test
public void contextShouldContainEnvAndPropertiesAndHostAndPort() throws Exception {
String hostname = "xx.xx.xx";
int port = 20;
DefaultAgentLaunchDescriptorImpl launchDescriptor = new DefaultAgentLaunchDescriptorImpl(hostname, port, new AgentBootstrapper());
AgentBootstrapperArgs bootstrapperArgs = new AgentBootstrapperArgs(new URL("https://" + hostname + ":" + port + "/go"), null, AgentBootstrapperArgs.SslMode.NONE);
DefaultAgentLaunchDescriptorImpl launchDescriptor = new DefaultAgentLaunchDescriptorImpl(bootstrapperArgs, new AgentBootstrapper());
Map context = launchDescriptor.context();
assertThat((String) context.get(AgentLaunchDescriptorKeys.HOSTNAME), is(hostname));
assertThat((Integer) context.get(AgentLaunchDescriptorKeys.PORT), is(port));
Set<String> envkeys = new HashSet<String>(System.getenv().keySet());
envkeys.removeAll(context.keySet());
assertThat(envkeys.isEmpty(), is(true));
Set<Object> propkeys = new HashSet<Object>(System.getProperties().keySet());
propkeys.removeAll(context.keySet());
assertThat(propkeys.isEmpty(), is(true));
assertEquals(context, bootstrapperArgs.toProperties());
}
}
View
Binary file not shown.
View

This file was deleted.

Oops, something went wrong.
View
@@ -29,9 +29,9 @@
FULL, NONE, NO_VERIFY_HOST
}
private static String SERVER_URL = "serverUrl";
private static String SSL_MODE = "sslVerificationMode";
private static String ROOT_CERT_FILE = "rootCertFile";
public static String SERVER_URL = "serverUrl";
public static String SSL_VERIFICATION_MODE = "sslVerificationMode";
public static String ROOT_CERT_FILE = "rootCertFile";
@Parameter(names = "-serverUrl", description = "The GoCD server URL. Must begin with `https://`, and end with `/go`", required = true, validateWith = ServerUrlValidator.class)
private URL serverUrl;
@@ -57,7 +57,7 @@ public AgentBootstrapperArgs(URL serverUrl, File rootCertFile, SslMode sslVerifi
public Properties toProperties() {
Properties properties = new Properties();
properties.put(SERVER_URL, serverUrl.toString());
properties.put(SSL_MODE, sslVerificationMode.name());
properties.put(SSL_VERIFICATION_MODE, sslVerificationMode.name());
if (rootCertFile != null) {
properties.put(ROOT_CERT_FILE, rootCertFile.getAbsoluteFile().toString());
@@ -71,7 +71,7 @@ public static AgentBootstrapperArgs fromProperties(Properties properties) {
URL serverUrl = new URL(properties.getProperty(SERVER_URL));
File rootCertFile = null;
SslMode sslVerificationMode = SslMode.valueOf(properties.getProperty(SSL_MODE));
SslMode sslVerificationMode = SslMode.valueOf(properties.getProperty(SSL_VERIFICATION_MODE));
if (properties.containsKey(ROOT_CERT_FILE)) {
rootCertFile = new File(properties.getProperty(ROOT_CERT_FILE));
View
@@ -0,0 +1,89 @@
/*
* 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.agent.common;
import com.thoughtworks.go.agent.ServerUrlGenerator;
import com.thoughtworks.go.util.SslVerificationMode;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.utils.URIBuilder;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.Map;
import static com.thoughtworks.go.util.ExceptionUtils.bomb;
public class AgentBootstrapperBackwardCompatibility {
private static final Log LOG = LogFactory.getLog(AgentBootstrapperBackwardCompatibility.class);
private final Map context;
public AgentBootstrapperBackwardCompatibility(Map context) {
this.context = context;
}
public File rootCertFile() {
return rootCertFileAsString() != null ? new File(rootCertFileAsString()) : null;
}
public String rootCertFileAsString() {
return context.containsKey(AgentBootstrapperArgs.ROOT_CERT_FILE) ? (String) context.get(AgentBootstrapperArgs.ROOT_CERT_FILE) : null;
}
public SslVerificationMode sslVerificationMode() {
try {
return SslVerificationMode.valueOf((String) context.get(AgentBootstrapperArgs.SSL_VERIFICATION_MODE));
} catch (Exception e) {
LOG.warn("SslVerificationMode could not parsed. Disabling SSL verification.");
return SslVerificationMode.NONE;
}
}
public ServerUrlGenerator getUrlGenerator() throws MalformedURLException {
return new UrlConstructor(serverUrl());
}
// Backward compatibility
// Bootstrappers <= 16.4 are invoked using java -jar agent-bootstrapper.jar 1.2.3.4 [8153]
// and they stuff "hostname" and "port" in the context, the new bootstrapper stuffs the (ssl) serverUrl directly
private String serverUrl() {
if (context.containsKey(AgentBootstrapperArgs.SERVER_URL)) {
return (String) context.get(AgentBootstrapperArgs.SERVER_URL);
} else {
return "http://" + context.get("hostname") + ":" + context.get("port") + "/go";
}
}
public String sslServerUrl(String sslPort) {
String serverUrl = serverUrl();
try {
// backward compatibility, since the agent.jar requires an ssl url, but the old bootstrapper does not have one.
URIBuilder url = new URIBuilder(serverUrl);
if (url.getScheme().equals("http")) {
url.setPort(Integer.valueOf(sslPort));
url.setScheme("https");
}
return url.toString();
} catch (URISyntaxException e) {
throw bomb(e);
}
}
}
View
@@ -18,17 +18,9 @@
import com.beust.jcommander.IParameterValidator;
import com.beust.jcommander.ParameterException;
import com.thoughtworks.go.agent.common.ssl.CertificateFileParser;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class CertificateFileValidator implements IParameterValidator {
@@ -43,37 +35,17 @@ public void validate(String name, String value) throws ParameterException {
}
try {
if (certificates(new File(value)).isEmpty()) {
if (new CertificateFileParser().certificates(new File(value)).isEmpty()) {
throw badCertfile(name);
}
} catch (Exception e) {
throw badCertfile(name);
}
}
private ParameterException badCertfile(String name) {
return new ParameterException(name + " must contain one or more X.509 certificates in DER encoded " +
"and may be supplied in binary or Base64 encoding");
}
public List<X509Certificate> certificates(File certFile) throws IOException, CertificateException {
ArrayList<X509Certificate> certs = new ArrayList<>();
if (certFile != null && certFile.exists() && certFile.canRead()) {
try (FileInputStream fis = new FileInputStream(certFile)) {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Collection<? extends Certificate> certificates = cf.generateCertificates(fis);
for (Certificate cert : certificates) {
if (cert instanceof X509Certificate) {
certs.add((X509Certificate) cert);
}
}
}
}
return certs;
}
}
View
@@ -0,0 +1,40 @@
/*
* 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.agent.common;
import com.thoughtworks.go.agent.ServerUrlGenerator;
import java.net.MalformedURLException;
public class UrlConstructor implements ServerUrlGenerator {
private final String serverUrl;
public UrlConstructor(String serverUrl) throws MalformedURLException {
if (serverUrl.endsWith("/")) {
serverUrl = serverUrl.substring(0, serverUrl.length() - 1);
}
this.serverUrl = serverUrl;
}
public String serverUrlFor(String subPath) {
if (subPath == null || subPath.trim().length() == 0) {
return serverUrl;
}
return serverUrl + "/" + subPath;
}
}
View
@@ -1,25 +1,25 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent.common.launcher;
import java.util.Map;
import com.thoughtworks.go.agent.ServerUrlGenerator;
import java.util.Map;
public interface AgentProcessParent {
int run(String launcherVersion, String launcherMd5, ServerUrlGenerator urlGenerator, Map<String, String> env);
int run(String launcherVersion, String launcherMd5, ServerUrlGenerator urlGenerator, Map<String, String> env, Map context);
}
View
@@ -1,80 +1,81 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent.launcher;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.thoughtworks.go.agent.ServerUrlGenerator;
import com.thoughtworks.go.agent.common.util.Downloader;
import com.thoughtworks.go.util.FileDigester;
import com.thoughtworks.go.util.PerfTimer;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.HeadMethod;
import com.thoughtworks.go.util.SslVerificationMode;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.NullOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import static java.lang.String.format;
public class ServerBinaryDownloader implements Downloader {
private final ServerCall serverCall = new ServerCall();
private static final Log LOG = LogFactory.getLog(ServerBinaryDownloader.class);
private static final String MD5_HEADER = "Content-MD5";
@Deprecated // for backward compatibility
private static final String SSL_PORT_HEADER = "Cruise-Server-Ssl-Port";
private final ServerUrlGenerator urlGenerator;
private File rootCertFile;
private String md5 = null;
private DownloadableFile downloadableFile;
private SslVerificationMode sslVerificationMode;
private String sslPort;
public static final class DownloadResult {
public final boolean performedDownload;
private final Map<String, String> headers;
private final ServerUrlGenerator urlGenerator;
public DownloadResult(boolean performedDownload, Map<String, String> headers, ServerUrlGenerator urlGenerator) {
public DownloadResult(boolean performedDownload) {
this.performedDownload = performedDownload;
this.headers = headers;
this.urlGenerator = urlGenerator;
}
public String serverBaseUrl() {
return urlGenerator.serverSslBaseUrl(Integer.parseInt(headers.get(SSL_PORT_HEADER)));
}
}
public ServerBinaryDownloader(ServerUrlGenerator urlGenerator, final DownloadableFile downloadableFile) {
public ServerBinaryDownloader(ServerUrlGenerator urlGenerator, final DownloadableFile downloadableFile, File rootCertFile, SslVerificationMode sslVerificationMode) {
this.rootCertFile = rootCertFile;
this.urlGenerator = urlGenerator;
this.downloadableFile = downloadableFile;
this.sslVerificationMode = sslVerificationMode;
}
public String md5() {
return md5;
}
public String sslPort() {
return sslPort;
}
public DownloadResult downloadAlways() {
boolean downloaded = false;
synchronized (downloadableFile.mutex()) {
@@ -92,10 +93,10 @@ public DownloadResult downloadAlways() {
}
}
}
return new DownloadResult(downloaded, null, urlGenerator);
return new DownloadResult(downloaded);
}
public DownloadResult downloadIfNecessary() {
public boolean downloadIfNecessary() {
synchronized (downloadableFile.mutex()) {
Map<String, String> headers = new HashMap<>();
boolean updated = false;
@@ -105,6 +106,7 @@ public DownloadResult downloadIfNecessary() {
headers = headers();
File localFile = new File(downloadableFile.getLocalFileName());
md5 = headers.get(MD5_HEADER);
sslPort = headers.get(SSL_PORT_HEADER);
if (!localFile.exists() || !checksOut(localFile, md5)) {
PerfTimer timer = PerfTimer.start("Downloading new " + downloadableFile + " with md5 signature: " + md5);
downloaded = download();
@@ -120,13 +122,15 @@ public DownloadResult downloadIfNecessary() {
} catch (InterruptedException ie) { /* we don't care. Stupid checked exception.*/ }
}
}
return new DownloadResult(downloaded, headers, urlGenerator);
return downloaded;
}
}
Map<String, String> headers() throws Exception {
Map<String, String> headers = ServerCall.invoke(new HeadMethod(checkUrl())).headers;
checkHeaders(headers, downloadableFile.url(urlGenerator));
Map<String, String> headers = serverCall.invoke(new HttpHead(checkUrl()), rootCertFile, sslVerificationMode).headers;
if (!headers.containsKey(MD5_HEADER)) {
LOG.error(format("Contacted server at URL %s but the server did not send back a response containing the header %s", downloadableFile.url(urlGenerator), MD5_HEADER));
}
return headers;
}
@@ -141,45 +145,24 @@ private String checkUrl() {
return url;
}
private static void checkHeaders(Map<String, String> headers, String url) {
if (!headers.containsKey(MD5_HEADER) || !headers.containsKey(SSL_PORT_HEADER)) {
LOG.error("Contacted server at URL " + url + " but it didn't give me the information I wanted. Please check the hostname and port.");
}
}
private static boolean checksOut(File file, String expectedSignature) {
FileInputStream input = null;
try {
try {
input = new FileInputStream(file);
FileDigester fileDigester = new FileDigester(input, new NullOutputStream());
fileDigester.copy();
return expectedSignature.equals(fileDigester.md5());
} finally {
if (input != null) {
input.close();
}
}
try (FileInputStream input = new FileInputStream(file)) {
FileDigester fileDigester = new FileDigester(input, new NullOutputStream());
fileDigester.copy();
return expectedSignature.equals(fileDigester.md5());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private boolean download() throws Exception {
HttpClient httpClient = new HttpClient();
HttpMethod method = new GetMethod(checkUrl());
InputStream body = null;
OutputStream outputFile = null;
httpClient.setConnectionTimeout(ServerCall.HTTP_TIMEOUT_IN_MILLISECONDS);
try {
LOG.info("download started at " + new Date());
final int status = httpClient.executeMethod(method);
if (status != 200) {
throw new Exception("Got status " + status + " " + method.getStatusText() + " from server");
}
body = new BufferedInputStream(method.getResponseBodyAsStream());
File toDownload = new File(downloadableFile.getLocalFileName());
try (OutputStream outputFile = new BufferedOutputStream(new FileOutputStream(toDownload))) {
LOG.info("download of " + toDownload + " started at " + new Date());
ServerCall.ServerResponseWrapper invoke = serverCall.invoke(new HttpGet(checkUrl()), rootCertFile, sslVerificationMode);
body = invoke.body;
LOG.info("got server response at " + new Date());
outputFile = new BufferedOutputStream(new FileOutputStream(new File(downloadableFile.getLocalFileName())));
IOUtils.copy(body, outputFile);
LOG.info("pipe the stream to " + downloadableFile + " at " + new Date());
return true;
@@ -189,8 +172,6 @@ private boolean download() throws Exception {
throw new Exception(message, e);
} finally {
IOUtils.closeQuietly(body);
IOUtils.closeQuietly(outputFile);
method.releaseConnection();
}
}
}
View
@@ -1,38 +1,40 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent.launcher;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import com.thoughtworks.go.agent.common.ssl.GoAgentServerHttpClientBuilder;
import com.thoughtworks.go.util.SslVerificationMode;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import java.io.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @understands calling any server url
@@ -41,35 +43,39 @@
private static final Log LOG = LogFactory.getLog(ServerCall.class);
public static final int HTTP_TIMEOUT_IN_MILLISECONDS = 5000;
public static ServerResponseWrapper invoke(HttpMethod method) throws Exception {
public ServerResponseWrapper invoke(HttpRequestBase request, File rootCertFile, SslVerificationMode sslVerificationMode) throws Exception {
HashMap<String, String> headers = new HashMap<>();
HttpClient httpClient = new HttpClient();
httpClient.setConnectionTimeout(HTTP_TIMEOUT_IN_MILLISECONDS);
try {
final int status = httpClient.executeMethod(method);
if (status == HttpStatus.SC_NOT_FOUND) {
HttpClientBuilder httpClientBuilder = new GoAgentServerHttpClientBuilder(rootCertFile, sslVerificationMode).httpClientBuilder(HttpClients.custom());
request.setConfig(RequestConfig.custom().setConnectTimeout(HTTP_TIMEOUT_IN_MILLISECONDS).build());
try (
CloseableHttpClient httpClient = httpClientBuilder.build();
final CloseableHttpResponse response = httpClient.execute(request);
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
out.println("Return Code: " + status);
PrintWriter out = new PrintWriter(sw)
) {
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
out.println("Return Code: " + response.getStatusLine().getStatusCode());
out.println("Few Possible Causes: ");
out.println("1. Your Go Server is down or not accessible.");
out.println("2. This agent might be incompatible with your Go Server.Please fix the version mismatch between Go Server and Go Agent.");
out.close();
throw new Exception(sw.toString());
}
if (status != HttpStatus.SC_OK) {
throw new Exception("Got status " + status + " " + method.getStatusText() + " from server");
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new Exception("Got status " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine() + " from server");
}
for (Header header : method.getResponseHeaders()) {
for (Header header : response.getAllHeaders()) {
headers.put(header.getName(), header.getValue());
}
return new ServerResponseWrapper(headers, method.getResponseBodyAsStream());
try (InputStream content = response.getEntity() != null ? response.getEntity().getContent() : null) {
return new ServerResponseWrapper(headers, content);
}
} catch (Exception e) {
String message = "Couldn't access Go Server with base url: " + method.getURI() + ": " + e.toString();
String message = "Couldn't access Go Server with base url: " + request.getURI() + ": " + e.toString();
LOG.error(message);
throw new Exception(message, e);
} finally {
method.releaseConnection();
}
}
@@ -86,10 +92,10 @@ private InputStream toByteArrayInputStream(InputStream body) throws IOException
if (body == null) {
return null;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(body, baos);
baos.close();
return new ByteArrayInputStream(baos.toByteArray());
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
IOUtils.copy(body, baos);
return new ByteArrayInputStream(baos.toByteArray());
}
}
}
}
View
@@ -0,0 +1,54 @@
/*
* 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.agent.common;
import com.thoughtworks.go.util.SslVerificationMode;
import org.junit.Test;
import java.io.File;
import java.net.URL;
import java.util.HashMap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class AgentBootstrapperBackwardCompatibilityTest {
@Test
public void shouldBeBackwardCompatible() throws Exception {
HashMap context = new HashMap();
context.put("hostname", "ci.example.com");
context.put("port", "8153");
AgentBootstrapperBackwardCompatibility compatibility = new AgentBootstrapperBackwardCompatibility(context);
assertNull(compatibility.rootCertFileAsString());
assertNull(compatibility.rootCertFile());
assertEquals(SslVerificationMode.NONE, compatibility.sslVerificationMode());
assertEquals("https://ci.example.com:8154/go", compatibility.sslServerUrl("8154"));
}
@Test
public void shouldReturnCLIArgsIfStuffedInContext() throws Exception {
AgentBootstrapperArgs args = new AgentBootstrapperArgs(new URL("https://go.example.com:8154/go"), new File("/path/to/certfile"), AgentBootstrapperArgs.SslMode.NO_VERIFY_HOST);
AgentBootstrapperBackwardCompatibility compatibility = new AgentBootstrapperBackwardCompatibility(args.toProperties());
assertEquals("/path/to/certfile", compatibility.rootCertFileAsString());
assertEquals(new File("/path/to/certfile"), compatibility.rootCertFile());
assertEquals(SslVerificationMode.NO_VERIFY_HOST, compatibility.sslVerificationMode());
assertEquals("https://go.example.com:8154/go", compatibility.sslServerUrl("8154"));
}
}
View
@@ -33,5 +33,22 @@ public void shouldValidateByParsingUrl() throws Exception {
new ServerUrlValidator().validate("foo", "bad-url");
}
@Test
public void shouldNotAllowUrlEndingWithoutGo() throws Exception {
expectedEx.expect(ParameterException.class);
expectedEx.expectMessage("must end with '/go' (https://localhost:8154/go)");
new ServerUrlValidator().validate("foo", "https://example.com");
}
@Test
public void shouldAllowSslUrlEndingWithGo() throws Exception {
new ServerUrlValidator().validate("foo", "https://example.com/go");
}
@Test
public void shouldNotAllowPlainTextUrlEndingWithGo() throws Exception {
expectedEx.expect(ParameterException.class);
expectedEx.expectMessage("must be an HTTPS url and must begin with https://");
new ServerUrlValidator().validate("foo", "http://example.com/go");
}
}
View
@@ -1,28 +1,30 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent.launcher;
import java.util.Map;
import com.thoughtworks.go.agent.testhelper.FakeBootstrapperServer;
import com.thoughtworks.go.mothers.ServerUrlGeneratorMother;
import com.thoughtworks.go.util.SslVerificationMode;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.Map;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
@@ -32,19 +34,27 @@
@Test
public void shouldGetAllHeaders() throws Exception {
ServerBinaryDownloader downloader = new ServerBinaryDownloader(ServerUrlGeneratorMother.generatorFor("localhost", 9090), DownloadableFile.AGENT);
ServerBinaryDownloader downloader = new ServerBinaryDownloader(ServerUrlGeneratorMother.generatorFor("localhost", 9090), DownloadableFile.AGENT, null, SslVerificationMode.NONE);
Map<String, String> headers = downloader.headers();
assertNotNull(headers.get("Content-MD5"));
assertThat(headers.get("Cruise-Server-Ssl-Port"), is("9443"));
}
@Test
public void shouldDownloadTheBinaryAlwaysIrrespectiveOfLocalFileChange() {
ServerBinaryDownloader downloader = new ServerBinaryDownloader(ServerUrlGeneratorMother.generatorFor("localhost", 9090), DownloadableFile.AGENT);
ServerBinaryDownloader downloader = new ServerBinaryDownloader(ServerUrlGeneratorMother.generatorFor("localhost", 9090), DownloadableFile.AGENT, null, SslVerificationMode.NONE);
ServerBinaryDownloader.DownloadResult result = downloader.downloadAlways();
assertThat(result.performedDownload,is(true));
assertThat(result.performedDownload, is(true));
result = downloader.downloadAlways();
assertThat(result.performedDownload,is(true));
assertThat(result.performedDownload, is(true));
}
@Test
public void shouldDownloadTheBinaryOverSSL() throws Exception {
ServerBinaryDownloader downloader = new ServerBinaryDownloader(ServerUrlGeneratorMother.generatorFor("https://localhost:9091/go"), DownloadableFile.AGENT, new File("testdata/test_cert.pem"), SslVerificationMode.NO_VERIFY_HOST);
ServerBinaryDownloader.DownloadResult result = downloader.downloadAlways();
assertThat(result.performedDownload, is(true));
result = downloader.downloadAlways();
assertThat(result.performedDownload, is(true));
}
}
View
@@ -1,53 +1,86 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent.launcher;
import java.util.List;
import com.thoughtworks.go.agent.testhelper.FakeBootstrapperServer;
import com.thoughtworks.go.mothers.ServerUrlGeneratorMother;
import org.apache.commons.httpclient.methods.GetMethod;
import com.thoughtworks.go.util.SslVerificationMode;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.HttpGet;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.List;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
@RunWith(FakeBootstrapperServer.class)
public class ServerCallTest {
@Test
public void shouldBeAbleToReadTheResponseBody() throws Exception {
GetMethod getMethod = new GetMethod(DownloadableFile.AGENT.url(ServerUrlGeneratorMother.generatorFor("localhost", 9090)));
ServerCall.ServerResponseWrapper response = ServerCall.invoke(getMethod);
HttpGet getMethod = new HttpGet(DownloadableFile.AGENT.url(ServerUrlGeneratorMother.generatorFor("localhost", 9090)));
ServerCall.ServerResponseWrapper response = new ServerCall().invoke(getMethod, null, SslVerificationMode.NONE);
List list = IOUtils.readLines(response.body);
assertThat(list.isEmpty(), is(false));
}
@Test
public void shouldThrowSpecifiCExceptionIncaseOf404() throws Exception {
GetMethod getMethod = new GetMethod("http://localhost:9090/go/not-found");
HttpGet getMethod = new HttpGet("http://localhost:9090/go/not-found");
try {
ServerCall.invoke(getMethod);
new ServerCall().invoke(getMethod, null, SslVerificationMode.NONE);
fail("Was expecting an exception!");
} catch (Exception ex) {
assertThat(ex.getMessage().contains(
"This agent might be incompatible with your Go Server."
+ "Please fix the version mismatch between Go Server and Go Agent."), is(true));
}
}
@Test
public void shouldConnectToAServerWithACertSignedByAKnownCA() throws Exception {
ServerCall.ServerResponseWrapper invoke = new ServerCall().invoke(new HttpGet("https://example.com"), null, SslVerificationMode.FULL);
assertThat(IOUtils.toString(invoke.body), containsString("This domain is established to be used for illustrative examples in documents"));
}
@Test
public void shouldConnectToAnSSLServerWithSelfSignedCertWhenInsecureModeIsInsecure() throws Exception {
ServerCall.ServerResponseWrapper invoke = new ServerCall().invoke(new HttpGet("https://localhost:9091/go/hello"), null, SslVerificationMode.NONE);
assertThat(IOUtils.toString(invoke.body).trim(), equalTo("Hello"));
}
@Test
public void shouldConnectToAnSSLServerWithSelfSignedCertWhenInsecureModeIsNoVerifyHost() throws Exception {
ServerCall.ServerResponseWrapper invoke = new ServerCall().invoke(new HttpGet("https://localhost:9091/go/hello"), new File("testdata/test_cert.pem"), SslVerificationMode.NO_VERIFY_HOST);
assertThat(IOUtils.toString(invoke.body).trim(), equalTo("Hello"));
}
@Test
public void shouldRaiseExceptionWhenSelfSignedCertDoesNotMatchTheHostName() throws Exception {
try {
new ServerCall().invoke(new HttpGet("https://localhost:9091/go/hello"), new File("testdata/test_cert.pem"), SslVerificationMode.FULL);
fail("Was expecting an exception!");
} catch (Exception expected) {
assertThat(expected.getMessage(), containsString("Host name 'localhost' does not match the certificate subject provided by the peer"));
}
}
}
View
Binary file not shown.
View
@@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIIDCjCCAfICBX3OuM15MA0GCSqGSIb3DQEBBQUAMEkxGTAXBgNVBAMTEElOanVoaWphcmkubG9j
YWwxLDAqBgNVBAsTI0NydWlzZSBzZXJ2ZXIgd2Vic2VydmVyIGNlcnRpZmljYXRlMB4XDTcwMDEw
MTAwMDAwMFoXDTI2MDQxMTEwMTQxMFowSTEZMBcGA1UEAxMQSU5qdWhpamFyaS5sb2NhbDEsMCoG
A1UECxMjQ3J1aXNlIHNlcnZlciB3ZWJzZXJ2ZXIgY2VydGlmaWNhdGUwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQCBL8Wn/n8jGOcHzJus22RrM/XqyNq1k11KNqFh5blvIUkLsbmveOSb
BpCzjnx7CtMB/fXF6VfapMDxF+068V9lOJx79GMbeuGxcU/iQX78sW8oC9TZFqbWUKdLO0MD3OBR
U2TJKl6wEOmetZU9CfMdWzAKK8jXQjYpVmfInhR5jmmeLf7pcnmhPbRhmyY9JB4PHHYRaT9MRbNu
lhF2Lhc2+tUIhAmntIhs9hlSadn2ab2+ZqysBs6Y8W/Z0lF7Vv1HaApMgBWidwToFY1iyUwiSwRr
JVMMp8m0Z/ZA68KtwEmi3PwcxRxnKskpwNCMXCcdhm8gBK+o5qpnzGgRVNfnAgMBAAEwDQYJKoZI
hvcNAQEFBQADggEBAADB3E9PMuf6ZM6uPxDktZG93wg99JWSU21z1h1DvzXekwKZEt7igYSSSBu1
cT2vf0YyIRml8YbvR0beWexajTVxLSHphKj1Cvp0kEQph4e2fs6Ipu+T8ZKN7rPigYEZmciE/sKy
y9x0Fb0z/fyo6dxP90cfbuutAJ6O/x/ZR4lkCzS9oFJr46/FAYkDQ95LA2Gz95oQZaSncFrtcyj2
a9VJoqXE03GMAr7E8o3Ltu2RHykMQzOtbA4EMoIqVFn1i3Z+7V7oxvrS4s7ABFpfEzXbsLUVIH/W
Pm+TEvFyyO1gsb7TAPubKyP74UCXshr4FzAiFvMQJD5xaoavFDkNanE=
-----END CERTIFICATE-----
View
@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- *************************GO-LICENSE-START******************************
* Copyright 2014 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.
*************************GO-LICENSE-END******************************* -->
<!--
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -126,6 +126,7 @@
<copy file="${project.basedir}/target/agent-launcher.jar" tofile="${main.dir}/agent-bootstrapper/testdata/agent-launcher.jar"/>
<copy file="${project.basedir}/target/agent-launcher.jar" tofile="${main.dir}/server/testdata/agent-launcher.jar"/>
<copy file="${project.basedir}/target/agent-launcher.jar" tofile="${main.dir}/agent-common/testdata/agent-launcher.jar"/>
</target>
</configuration>
</execution>
View
@@ -1,42 +1,40 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.cruise.agent.launcher;
import com.thoughtworks.go.agent.ServerUrlGenerator;
import com.thoughtworks.cruise.agent.common.launcher.AgentLaunchDescriptor;
import com.thoughtworks.cruise.agent.common.launcher.AgentLauncher;
import com.thoughtworks.go.agent.ServerUrlGenerator;
import com.thoughtworks.go.agent.common.AgentBootstrapperBackwardCompatibility;
import com.thoughtworks.go.agent.common.launcher.AgentProcessParent;
import com.thoughtworks.go.agent.common.util.Downloader;
import com.thoughtworks.go.agent.common.util.JarUtil;
import com.thoughtworks.go.agent.common.util.LoggingHelper;
import com.thoughtworks.go.agent.launcher.DownloadableFile;
import com.thoughtworks.go.agent.launcher.Lockfile;
import com.thoughtworks.go.agent.launcher.ServerBinaryDownloader;
import com.thoughtworks.go.agent.launcher.UrlConstructor;
import com.thoughtworks.go.util.SslVerificationMode;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import static com.thoughtworks.cruise.agent.common.launcher.AgentLaunchDescriptorKeys.HOSTNAME;
import static com.thoughtworks.cruise.agent.common.launcher.AgentLaunchDescriptorKeys.PORT;
public class AgentLauncherImpl implements AgentLauncher {
public static final int UNKNOWN_EXCEPTION_OCCURRED = -273;
@@ -72,19 +70,22 @@ public int launch(AgentLaunchDescriptor descriptor) {
shutdownHook = registerShutdownHook();
ServerUrlGenerator urlGenerator = getUrlGenerator(descriptor);
Map context = descriptor.context();
ServerBinaryDownloader launcherDownloader = new ServerBinaryDownloader(urlGenerator, DownloadableFile.LAUNCHER);
ServerBinaryDownloader.DownloadResult downloadResult = launcherDownloader.downloadIfNecessary();
AgentBootstrapperBackwardCompatibility backwardCompatibility = backwardCompatibility(context);
ServerUrlGenerator urlGenerator = backwardCompatibility.getUrlGenerator();
File rootCertFile = backwardCompatibility.rootCertFile();
SslVerificationMode sslVerificationMode = backwardCompatibility.sslVerificationMode();
if (downloadResult.performedDownload) {
ServerBinaryDownloader launcherDownloader = new ServerBinaryDownloader(urlGenerator, DownloadableFile.LAUNCHER, rootCertFile, sslVerificationMode);
if (launcherDownloader.downloadIfNecessary()) {
return LAUNCHER_NOT_UP_TO_DATE;
}
ServerBinaryDownloader agentDownloader = new ServerBinaryDownloader(urlGenerator, DownloadableFile.AGENT);
ServerBinaryDownloader agentDownloader = new ServerBinaryDownloader(urlGenerator, DownloadableFile.AGENT, rootCertFile, sslVerificationMode);
agentDownloader.downloadIfNecessary();
returnValue = agentProcessParentRunner.run(getLauncherVersion(), launcherDownloader.md5(), urlGenerator, System.getenv());
returnValue = agentProcessParentRunner.run(getLauncherVersion(), launcherDownloader.md5(), urlGenerator, System.getenv(), context);
try {
// Sleep a bit so that if there are problems we don't spin
@@ -103,6 +104,10 @@ public int launch(AgentLaunchDescriptor descriptor) {
}
}
private AgentBootstrapperBackwardCompatibility backwardCompatibility(Map context) {
return new AgentBootstrapperBackwardCompatibility(context);
}
private void removeShutDownHook(Thread shutdownHook) {
if (shutdownHook != null) {
try {
@@ -114,40 +119,27 @@ private void removeShutDownHook(Thread shutdownHook) {
private Thread registerShutdownHook() {
Thread shutdownHook = new Thread() {
@Override public void run() {
lockFile.delete();
@Override
public void run() {
lockFile.delete();
}
};
Runtime.getRuntime().addShutdownHook(shutdownHook);
return shutdownHook;
}
private ServerUrlGenerator getUrlGenerator(AgentLaunchDescriptor descriptor) {
String hostName = getHostName(descriptor);
int port = getPort(descriptor);
return new UrlConstructor(hostName, port);
}
private String getLauncherVersion() throws IOException {
return JarUtil.getGoVersion(Downloader.AGENT_LAUNCHER);
}
private int getPort(AgentLaunchDescriptor descriptor) {
return ((Integer) descriptor.context().get(PORT)).intValue();
}
private String getHostName(AgentLaunchDescriptor descriptor) {
return (String) descriptor.context().get(HOSTNAME);
}
public static interface AgentProcessParentRunner {
int run(String launcherVersion, String launcherMd5, ServerUrlGenerator urlGenerator, Map<String, String> environmentVariables);
int run(String launcherVersion, String launcherMd5, ServerUrlGenerator urlGenerator, Map<String, String> environmentVariables, Map context);
}
private static class AgentJarBasedAgentParentRunner implements AgentProcessParentRunner {
public int run(String launcherVersion, String launcherMd5, ServerUrlGenerator urlGenerator, Map<String, String> environmentVariables) {
public int run(String launcherVersion, String launcherMd5, ServerUrlGenerator urlGenerator, Map<String, String> environmentVariables, Map context) {
AgentProcessParent agentProcessParent = (AgentProcessParent) JarUtil.objectFromJar(Downloader.AGENT_BINARY, GO_AGENT_BOOTSTRAP_CLASS);
return agentProcessParent.run(launcherVersion, launcherMd5, urlGenerator, environmentVariables);
return agentProcessParent.run(launcherVersion, launcherMd5, urlGenerator, environmentVariables, context);
}
}
View

This file was deleted.

Oops, something went wrong.
View
@@ -1,38 +1,27 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent.launcher;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import com.googlecode.junit.ext.checkers.OSChecker;
import com.thoughtworks.cruise.agent.launcher.AgentLauncherImpl;
import com.thoughtworks.go.agent.ServerUrlGenerator;
import com.thoughtworks.cruise.agent.common.launcher.AgentLaunchDescriptor;
import com.thoughtworks.cruise.agent.common.launcher.AgentLaunchDescriptorKeys;
import com.thoughtworks.cruise.agent.common.launcher.AgentLauncher;
import com.thoughtworks.cruise.agent.launcher.AgentLauncherImpl;
import com.thoughtworks.go.agent.ServerUrlGenerator;
import com.thoughtworks.go.agent.common.AgentBootstrapperArgs;
import com.thoughtworks.go.agent.common.util.Downloader;
import com.thoughtworks.go.agent.common.util.JarUtil;
import com.thoughtworks.go.agent.testhelper.FakeBootstrapperServer;
@@ -43,6 +32,17 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertThat;
@@ -73,7 +73,7 @@ public void shouldPassLauncherVersionToAgent() throws InterruptedException, IOEx
final String version = "12.3";
final List<String> actualVersion = new ArrayList<String>();
final AgentLauncher launcher = new AgentLauncherImpl(new AgentLauncherImpl.AgentProcessParentRunner() {
public int run(String launcherVersion, String launcherMd5, ServerUrlGenerator urlConstructor, Map<String, String> environmentVariables) {
public int run(String launcherVersion, String launcherMd5, ServerUrlGenerator urlConstructor, Map<String, String> environmentVariables, Map context) {
actualVersion.add(launcherVersion);
return 0;
}
@@ -92,7 +92,7 @@ public int run(String launcherVersion, String launcherMd5, ServerUrlGenerator ur
@Test
public void shouldNotThrowException_insteedReturnAppropriateErrorCode_whenSomethingGoesWrongInLaunch() {
AgentLaunchDescriptor launchDesc = mock(AgentLaunchDescriptor.class);
when((String) launchDesc.context().get(AgentLaunchDescriptorKeys.HOSTNAME)).thenThrow(new RuntimeException("Ouch!"));
when((String) launchDesc.context().get(AgentBootstrapperArgs.SERVER_URL)).thenThrow(new RuntimeException("Ouch!"));
try {
assertThat(new AgentLauncherImpl().launch(launchDesc), is(-273));
} catch (Exception e) {
@@ -103,8 +103,8 @@ public void shouldNotThrowException_insteedReturnAppropriateErrorCode_whenSometh
private AgentLaunchDescriptor launchDescriptor() {
AgentLaunchDescriptor launchDescriptor = mock(AgentLaunchDescriptor.class);
Map contextMap = new ConcurrentHashMap();
contextMap.put(AgentLaunchDescriptorKeys.HOSTNAME, "localhost");
contextMap.put(AgentLaunchDescriptorKeys.PORT, 9090);
contextMap.put(AgentBootstrapperArgs.SERVER_URL, "http://localhost:9090/go");
contextMap.put(AgentBootstrapperArgs.SSL_VERIFICATION_MODE, "NONE");
when(launchDescriptor.context()).thenReturn(contextMap);
return launchDescriptor;
}
View
@@ -1,30 +1,34 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent.launcher;
import com.thoughtworks.go.agent.common.UrlConstructor;
import com.thoughtworks.go.util.SslVerificationMode;
import org.junit.Test;
import java.net.MalformedURLException;
import static org.junit.Assert.fail;
public class ServerAgentSignatureFinderTest {
@Test
public void shouldThrowExceptionIfUrlCannotBeContacted() {
final UrlConstructor urlConstructor = new UrlConstructor("www.uiookbkweruoyiuygfihkjhqkwehkq.com", 80);
ServerBinaryDownloader signatureFinder = new ServerBinaryDownloader(urlConstructor, DownloadableFile.AGENT);
public void shouldThrowExceptionIfUrlCannotBeContacted() throws MalformedURLException {
final UrlConstructor urlConstructor = new UrlConstructor("https://www.uiookbkweruoyiuygfihkjhqkwehkq.com:8154/go");
ServerBinaryDownloader signatureFinder = new ServerBinaryDownloader(urlConstructor, DownloadableFile.AGENT, null, SslVerificationMode.NONE);
try {
signatureFinder.headers();
fail("Shouldn't work if server doesn't exist");
View
@@ -1,37 +1,35 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent.launcher;
import com.thoughtworks.go.agent.common.UrlConstructor;
import org.junit.Test;
import java.net.MalformedURLException;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
public class UrlConstructorTest {
@Test
public void shouldGenerateCorrectUrlForGivenPath() {
UrlConstructor urlConstructor = new UrlConstructor("localhost", 8080);
assertThat(urlConstructor.serverUrlFor("foo/bar"), is("http://localhost:8080/go/foo/bar"));
assertThat(urlConstructor.serverUrlFor("admin/agent"), is("http://localhost:8080/go/admin/agent"));
}
@Test
public void shouldGenerateCorrectServerBaseUrl() {
UrlConstructor urlConstructor = new UrlConstructor("localhost", 8080);
assertThat(urlConstructor.serverSslBaseUrl(8443), is("https://localhost:8443/go/"));
public void shouldGenerateCorrectUrlForGivenPath() throws MalformedURLException {
UrlConstructor urlConstructor = new UrlConstructor("https://example.com:8443/go/");
assertThat(urlConstructor.serverUrlFor(""), is("https://example.com:8443/go"));
assertThat(urlConstructor.serverUrlFor("foo/bar"), is("https://example.com:8443/go/foo/bar"));
assertThat(urlConstructor.serverUrlFor("admin/agent"), is("https://example.com:8443/go/admin/agent"));
}
}
View
Binary file not shown.
View
@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- *************************GO-LICENSE-START******************************
* Copyright 2015 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.
*************************GO-LICENSE-END******************************* -->
<!--
~ 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.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -23,110 +23,100 @@
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"
default-init-method="init">
<import resource="classpath:applicationContext-plugin-infra.xml"/>
<context:annotation-config/>
<!-- Loads the System Properties -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:agent.properties</value>
</list>
</property>
<!--SYSTEM_PROPERTIES_MODE_OVERRIDE : Check system properties first, before trying the specified properties.
This allows system properties to override any other property source.-->
<property name="systemPropertiesMode" value="2"/>
</bean>
<bean id="log4jDirectConfigurer" class="com.thoughtworks.go.util.Log4jDirectConfigurer" />
<bean id="buildLoopServer" class="com.thoughtworks.go.agent.service.HttpInvokerProxyFactoryWrapper"
p:serviceInterface="com.thoughtworks.go.remote.BuildRepositoryRemote">
<property name="httpInvokerRequestExecutor">
<bean class="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor">
<property name="httpClient" ref="httpClient"/>
</bean>
</property>
</bean>
<bean class="com.thoughtworks.go.util.URLService"/>
<bean class="com.thoughtworks.go.util.HttpService"/>
<bean class="com.thoughtworks.go.publishers.GoArtifactsManipulator"/>
<bean class="com.thoughtworks.go.agent.service.SslInfrastructureService"/>
<bean class="com.thoughtworks.go.agent.service.AgentUpgradeService"/>
<bean class="com.thoughtworks.go.config.DefaultAgentRegistry" />
<bean class="com.thoughtworks.go.agent.service.AgentWebsocketService" />
<bean id="subprocessLogger" class="com.thoughtworks.go.util.SubprocessLogger"/>
<bean id="agentController" class="com.thoughtworks.go.agent.AgentController"/>
<bean id="agentPluginsInitializer" class="com.thoughtworks.go.agent.AgentPluginsInitializer"/>
<bean class="com.thoughtworks.go.plugin.access.packagematerial.PackageAsRepositoryExtension"/>
<bean class="com.thoughtworks.go.plugin.access.scm.SCMExtension"/>
<bean class="com.thoughtworks.go.plugin.access.pluggabletask.TaskExtension"/>
<bean id="httpClient" class="org.apache.commons.httpclient.HttpClient">
<constructor-arg>
<ref bean="httpConnectionManager"/>
</constructor-arg>
</bean>
<bean id="httpConnectionManager" class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager"
p:params-ref="httpConnectionParams">
</bean>
<bean id="httpConnectionParams" class="org.apache.commons.httpclient.params.HttpConnectionManagerParams"
p:soTimeout="300000"
p:connectionTimeout="300000">
</bean>
<bean id="agentControllerLooper" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"
p:targetObject-ref="agentController"
p:targetMethod="loop"/>
<bean id="agentControllerPinger" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"
p:targetObject-ref="agentController"
p:targetMethod="ping"/>
<bean id="agentControllerInstructionExecutor" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"
p:targetObject-ref="agentController"
p:targetMethod="executeAgentInstruction"/>
<!-- worker thread -->
<bean name="loopThread" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<bean class="org.springframework.scheduling.timer.ScheduledTimerTask"
p:delay="${agent.get.work.delay}"
p:period="${agent.get.work.interval}"
p:timerTask-ref="agentControllerLooper"/>
</list>
</property>
</bean>
<!-- ping thread -->
<bean name="pingThread" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<bean class="org.springframework.scheduling.timer.ScheduledTimerTask"
p:delay="${agent.ping.delay}"
p:period="${agent.ping.interval}"
p:fixedRate="true"
p:timerTask-ref="agentControllerPinger"/>
</list>
</property>
</bean>
<!-- instruction checker -->
<bean name="instructionExecuteThread" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<bean class="org.springframework.scheduling.timer.ScheduledTimerTask"
p:delay="${agent.instruction.delay}"
p:period="${agent.instruction.interval}"
p:timerTask-ref="agentControllerInstructionExecutor"/>
</list>
</property>
</bean>
<import resource="classpath:applicationContext-plugin-infra.xml"/>
<context:annotation-config/>
<!-- Loads the System Properties -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:agent.properties</value>
</list>
</property>
<!--SYSTEM_PROPERTIES_MODE_OVERRIDE : Check system properties first, before trying the specified properties.
This allows system properties to override any other property source.-->
<property name="systemPropertiesMode" value="2"/>
</bean>
<bean id="log4jDirectConfigurer" class="com.thoughtworks.go.util.Log4jDirectConfigurer"/>
<bean id="buildLoopServer" class="com.thoughtworks.go.agent.service.HttpInvokerProxyFactoryWrapper"
p:serviceInterface="com.thoughtworks.go.remote.BuildRepositoryRemote">
<property name="httpInvokerRequestExecutor">
<bean class="com.thoughtworks.go.agent.GoHttpClientHttpInvokerRequestExecutor">
<constructor-arg ref="httpClient"/>
</bean>
</property>
</bean>
<bean class="com.thoughtworks.go.util.URLService"/>
<bean class="com.thoughtworks.go.util.HttpService"/>
<bean class="com.thoughtworks.go.publishers.GoArtifactsManipulator"/>
<bean class="com.thoughtworks.go.agent.service.SslInfrastructureService"/>
<bean class="com.thoughtworks.go.agent.service.AgentUpgradeService"/>
<bean class="com.thoughtworks.go.config.DefaultAgentRegistry"/>
<bean class="com.thoughtworks.go.agent.service.AgentWebsocketService"/>
<bean id="subprocessLogger" class="com.thoughtworks.go.util.SubprocessLogger"/>
<bean id="agentController" class="com.thoughtworks.go.agent.AgentController"/>
<bean id="agentPluginsInitializer" class="com.thoughtworks.go.agent.AgentPluginsInitializer"/>
<bean class="com.thoughtworks.go.plugin.access.packagematerial.PackageAsRepositoryExtension"/>
<bean class="com.thoughtworks.go.plugin.access.scm.SCMExtension"/>
<bean class="com.thoughtworks.go.plugin.access.pluggabletask.TaskExtension"/>
<bean id="httpClient" class="com.thoughtworks.go.agent.common.ssl.GoAgentServerHttpClient">
<constructor-arg ref="systemEnvironment"/>
</bean>
<bean id="agentControllerLooper" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"
p:targetObject-ref="agentController"
p:targetMethod="loop"/>
<bean id="agentControllerPinger" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"
p:targetObject-ref="agentController"
p:targetMethod="ping"/>
<bean id="agentControllerInstructionExecutor"
class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"
p:targetObject-ref="agentController"
p:targetMethod="executeAgentInstruction"/>
<!-- worker thread -->
<bean name="loopThread" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<bean class="org.springframework.scheduling.timer.ScheduledTimerTask"
p:delay="${agent.get.work.delay}"
p:period="${agent.get.work.interval}"
p:timerTask-ref="agentControllerLooper"/>
</list>
</property>
</bean>
<!-- ping thread -->
<bean name="pingThread" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<bean class="org.springframework.scheduling.timer.ScheduledTimerTask"
p:delay="${agent.ping.delay}"
p:period="${agent.ping.interval}"
p:fixedRate="true"
p:timerTask-ref="agentControllerPinger"/>
</list>
</property>
</bean>
<!-- instruction checker -->
<bean name="instructionExecuteThread" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<bean class="org.springframework.scheduling.timer.ScheduledTimerTask"
p:delay="${agent.instruction.delay}"
p:period="${agent.instruction.interval}"
p:timerTask-ref="agentControllerInstructionExecutor"/>
</list>
</property>
</bean>
</beans>
View
@@ -19,12 +19,14 @@
import com.thoughtworks.go.agent.service.AgentUpgradeService;
import com.thoughtworks.go.agent.service.AgentWebsocketService;
import com.thoughtworks.go.agent.service.SslInfrastructureService;
import com.thoughtworks.go.buildsession.ArtifactsRepository;
import com.thoughtworks.go.buildsession.BuildSession;
import com.thoughtworks.go.buildsession.BuildVariables;
import com.thoughtworks.go.config.AgentAutoRegistrationProperties;
import com.thoughtworks.go.config.AgentRegistry;
import com.thoughtworks.go.domain.*;
import com.thoughtworks.go.buildsession.ArtifactsRepository;
import com.thoughtworks.go.buildsession.BuildSession;
import com.thoughtworks.go.domain.AgentRuntimeStatus;
import com.thoughtworks.go.domain.AgentStatus;
import com.thoughtworks.go.domain.BuildSettings;
import com.thoughtworks.go.domain.exception.UnregisteredAgentException;
import com.thoughtworks.go.plugin.access.packagematerial.PackageAsRepositoryExtension;
import com.thoughtworks.go.plugin.access.pluggabletask.TaskExtension;
@@ -320,8 +322,7 @@ private void runBuild(BuildSettings buildSettings) {
ConsoleOutputTransmitter buildConsole = new ConsoleOutputTransmitter(
new RemoteConsoleAppender(
urlService.prefixPartialUrl(buildSettings.getConsoleUrl()),
httpService,
agentRuntimeInfo.getIdentifier()));
httpService));
ArtifactsRepository artifactsRepository = new UrlBasedArtifactsRepository(
httpService,
urlService.prefixPartialUrl(buildSettings.getArtifactUploadBaseUrl()),
View
@@ -1,56 +1,42 @@
/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
/*
* 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
* 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.
*************************GO-LICENSE-END***********************************/
*/
package com.thoughtworks.go.agent;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.thoughtworks.go.agent.common.AgentBootstrapperArgs;
import com.thoughtworks.go.agent.common.AgentCLI;
import com.thoughtworks.go.agent.common.util.LoggingHelper;
import com.thoughtworks.go.util.GoConstants;
import com.thoughtworks.go.util.SystemEnvironment;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class AgentMain {
private static final String QUOTE = "\"";
public static void main(String... argv) throws Exception {
AgentBootstrapperArgs args = new AgentCLI().parse(argv);
private AgentMain() {
}
LoggingHelper.configureLoggerIfNoneExists("go-agent.log", "go-agent-log4j.properties");
new SystemEnvironment().setProperty(SystemEnvironment.SERVICE_URL, args.getServerUrl().toString());
new SystemEnvironment().setProperty(SystemEnvironment.AGENT_SSL_VERIFICATION_MODE, args.getSslMode().toString());
public static void main(String... args) throws Exception {
if (args.length != 1) {
throw new RuntimeException(
"Usage: java -jar agent.jar https://<cruise server hostname>:<cruise server port>/go/");
if (args.getRootCertFile() != null) {
new SystemEnvironment().setProperty(SystemEnvironment.AGENT_ROOT_CERT_FILE, args.getRootCertFile().toString());
}
LoggingHelper.configureLoggerIfNoneExists("go-agent.log", "go-agent-log4j.properties");
setServiceUrl(args[0]);
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
}
static void setServiceUrl(String url) {
String target = String.format(".*(%s/?)$", GoConstants.OLD_URL_CONTEXT);
Pattern pattern = Pattern.compile(target);
Matcher matcher = pattern.matcher(url);
if (matcher.matches()) {
String context = matcher.group(1);
url = url.substring(0, url.lastIndexOf(context)) + GoConstants.GO_URL_CONTEXT + "/";
}
new SystemEnvironment().setProperty("serviceUrl", url);
}
}
Oops, something went wrong.