Skip to content

Commit

Permalink
Add support of next-gen azure linux agents
Browse files Browse the repository at this point in the history
  • Loading branch information
dtretyakov committed Nov 16, 2016
1 parent 669cf9f commit b98f134
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
import jetbrains.buildServer.agent.BuildAgentConfigurationEx;
import jetbrains.buildServer.util.FileUtil;
import jetbrains.buildServer.util.StringUtil;
import org.apache.commons.codec.binary.Base64;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.xpath.XPath;
import org.jetbrains.annotations.NotNull;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
* Reads configuration settings on Unix.
Expand All @@ -21,6 +25,7 @@ public class UnixConfigReader extends AgentConfigReader {
private static final String UNIX_CONFIG_DIR = "/var/lib/waagent/";
private static final String UNIX_PROP_FILE = UNIX_CONFIG_DIR + "SharedConfig.xml";
private static final String UNIX_CUSTOM_DATA_FILE = UNIX_CONFIG_DIR + "ovf-env.xml";
private static final String WINDOWSAZURE_NAMESPACE = "http://schemas.microsoft.com/windowsazure";
private final FileUtils myFileUtils;

public UnixConfigReader(@NotNull final BuildAgentConfigurationEx agentConfiguration,
Expand Down Expand Up @@ -75,19 +80,49 @@ public void process() {
}

private void readCustomData(@NotNull final Element documentElement) throws JDOMException {
final XPath xPath = XPath.newInstance("string(//wa:LinuxProvisioningConfigurationSet/wa:CustomData)");
//noinspection unchecked
final List<Namespace> namespaces = new ArrayList<Namespace>(documentElement.getAdditionalNamespaces());
namespaces.add(documentElement.getNamespace());

String prefix = null;
for (Namespace namespace : namespaces) {
if (namespace.getURI().equals(WINDOWSAZURE_NAMESPACE)) {
prefix = namespace.getPrefix();
break;
}
}

if (prefix == null) {
LOG.warn(String.format("Unable to find %s namespace in file %s", WINDOWSAZURE_NAMESPACE, UNIX_CUSTOM_DATA_FILE));
return;
}

final String customDataQuery = String.format("string(//%s:LinuxProvisioningConfigurationSet/%s:CustomData)", prefix, prefix);
final XPath xPath = XPath.newInstance(customDataQuery);
final Object value = xPath.selectSingleNode(documentElement);
if (value == null) {
LOG.warn(String.format("Unable to read CustomData element in file %s", UNIX_CUSTOM_DATA_FILE));
return;
}

final String serializedCustomData = String.valueOf(value);
String serializedCustomData = String.valueOf(value);
if (StringUtil.isEmpty(serializedCustomData)) {
LOG.warn(String.format("CustomData element in file %s is empty", UNIX_CUSTOM_DATA_FILE));
return;
}

final byte[] bytes = serializedCustomData.getBytes();
if (!Base64.isArrayByteBase64(bytes)) {
LOG.warn(String.format("CustomData value should be Base64 encoded in file %s is empty", UNIX_CUSTOM_DATA_FILE));
return;
}

// New azure linux agent execute additional Base64 encode
final byte[] decodedBytes = Base64.decodeBase64(bytes);
if (Base64.isArrayByteBase64(decodedBytes)) {
serializedCustomData = new String(decodedBytes);
}

processCustomData(serializedCustomData);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,13 @@ public void process() {
final String customData = myFileUtils.readFile(customDataFile);
if (StringUtil.isEmpty(customData)) {
LOG.info(String.format(CUSTOM_DATA_FILE_IS_EMPTY, customDataFile));
return;
}

// Process custom data
try {
processCustomData(customData);
} catch (Exception e) {
LOG.warnAndDebugDetails(String.format(UNABLE_TO_READ_CUSTOM_DATA_FILE, customDataFile), e);
} else {
// Process custom data
try {
processCustomData(customData);
} catch (Exception e) {
LOG.warnAndDebugDetails(String.format(UNABLE_TO_READ_CUSTOM_DATA_FILE, customDataFile), e);
}
}

// Check properties file existence
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package jetbrains.buildServer.clouds.azure;

import jetbrains.buildServer.agent.BuildAgentConfigurationEx;
import jetbrains.buildServer.util.CollectionsUtil;
import jetbrains.buildServer.util.FileUtil;
import jetbrains.buildServer.util.StringUtil;
import org.jmock.Expectations;
Expand Down Expand Up @@ -28,23 +29,57 @@ public void testProcessUnixConfig() throws IOException {
final IdleShutdown idleShutdown = m.mock(IdleShutdown.class);

m.checking(new Expectations() {{
allowing(fileUtils).readFile(new File("/var/lib/waagent/SharedConfig.xml"));
one(fileUtils).readFile(new File("/var/lib/waagent/SharedConfig.xml"));
will(returnValue(FileUtil.readText(new File("src/test/resources/SharedConfig.xml"))));

allowing(agentConfiguration).setOwnPort(9090);
allowing(agentConfiguration).addAlternativeAgentAddress("191.233.107.5");
allowing(agentConfiguration).setName("paksvvm-53eb78da");
allowing(agentConfiguration).setServerUrl("http://tc-srv.cloudapp.net:8111");
allowing(agentConfiguration).getConfigurationParameters();
one(agentConfiguration).setOwnPort(9090);
one(agentConfiguration).addAlternativeAgentAddress("191.233.107.5");
one(agentConfiguration).setServerUrl("http://tc-srv.cloudapp.net:8111");
one(agentConfiguration).getConfigurationParameters();
will(returnValue(Collections.emptyMap()));
allowing(agentConfiguration).addConfigurationParameter(AzurePropertiesNames.INSTANCE_NAME, "paksvvm-53eb78da");
allowing(agentConfiguration).addConfigurationParameter("system.cloud.profile_id", "cp1");
allowing(agentConfiguration).addConfigurationParameter("teamcity.cloud.instance.hash", "Nx50NAfzeoljh3iJf77jvtci1BSWtaZ2");
one(agentConfiguration).addConfigurationParameter(AzurePropertiesNames.INSTANCE_NAME, "paksvvm-53eb78da");
one(agentConfiguration).addConfigurationParameter("system.cloud.profile_id", "cp1");
one(agentConfiguration).addConfigurationParameter("teamcity.cloud.instance.hash", "Nx50NAfzeoljh3iJf77jvtci1BSWtaZ2");

allowing(fileUtils).readFile(new File("/var/lib/waagent/ovf-env.xml"));
one(fileUtils).readFile(new File("/var/lib/waagent/ovf-env.xml"));
will(returnValue(FileUtil.readText(new File("src/test/resources/ovf-env.xml"))));

allowing(idleShutdown).setIdleTime(2400000L);
one(idleShutdown).setIdleTime(2400000L);
}});

UnixConfigReader configReader = new UnixConfigReader(agentConfiguration, idleShutdown, fileUtils);
configReader.process();

m.assertIsSatisfied();
}

@Test
public void testProcessUnixConfig2() throws IOException {
final Mockery m = new Mockery() {{
setImposteriser(ClassImposteriser.INSTANCE);
}};
final FileUtils fileUtils = m.mock(FileUtils.class);
final BuildAgentConfigurationEx agentConfiguration = m.mock(BuildAgentConfigurationEx.class);
final IdleShutdown idleShutdown = m.mock(IdleShutdown.class);

m.checking(new Expectations() {{
one(fileUtils).readFile(new File("/var/lib/waagent/SharedConfig.xml"));
will(returnValue(FileUtil.readText(new File("src/test/resources/SharedConfig.xml"))));

one(agentConfiguration).setOwnPort(9090);
one(agentConfiguration).addAlternativeAgentAddress("191.233.107.5");
one(agentConfiguration).setName("paksvvm-53eb78da");
one(agentConfiguration).setServerUrl("http://tc-srv.cloudapp.net:8111");
one(agentConfiguration).getConfigurationParameters();
will(returnValue(CollectionsUtil.asMap(AzurePropertiesNames.INSTANCE_NAME, "")));
one(agentConfiguration).addConfigurationParameter(AzurePropertiesNames.INSTANCE_NAME, "paksvvm-53eb78da");
one(agentConfiguration).addConfigurationParameter("system.cloud.profile_id", "cp1");
one(agentConfiguration).addConfigurationParameter("teamcity.cloud.instance.hash", "Nx50NAfzeoljh3iJf77jvtci1BSWtaZ2");

one(fileUtils).readFile(new File("/var/lib/waagent/ovf-env.xml"));
will(returnValue(FileUtil.readText(new File("src/test/resources/ovf-env2.xml"))));

one(idleShutdown).setIdleTime(2400000L);
}});

UnixConfigReader configReader = new UnixConfigReader(agentConfiguration, idleShutdown, fileUtils);
Expand All @@ -63,16 +98,16 @@ public void testDisableIntegrationWithoutCustomDataFile() throws IOException {
final IdleShutdown idleShutdown = m.mock(IdleShutdown.class);

m.checking(new Expectations() {{
allowing(fileUtils).readFile(new File("/var/lib/waagent/SharedConfig.xml"));
one(fileUtils).readFile(new File("/var/lib/waagent/SharedConfig.xml"));
will(returnValue(FileUtil.readText(new File("src/test/resources/SharedConfig.xml"))));

allowing(agentConfiguration).setOwnPort(9090);
allowing(agentConfiguration).addAlternativeAgentAddress("191.233.107.5");
allowing(agentConfiguration).getConfigurationParameters();
one(agentConfiguration).setOwnPort(9090);
one(agentConfiguration).addAlternativeAgentAddress("191.233.107.5");
one(agentConfiguration).getConfigurationParameters();
will(returnValue(Collections.emptyMap()));
allowing(agentConfiguration).addConfigurationParameter(AzurePropertiesNames.INSTANCE_NAME, "paksvvm-53eb78da");
one(agentConfiguration).addConfigurationParameter(AzurePropertiesNames.INSTANCE_NAME, "paksvvm-53eb78da");

allowing(fileUtils).readFile(new File("/var/lib/waagent/ovf-env.xml"));
one(fileUtils).readFile(new File("/var/lib/waagent/ovf-env.xml"));
will(returnValue(StringUtil.EMPTY));
}});

Expand All @@ -92,10 +127,10 @@ public void testDisableIntegrationWithoutPropertiesFile() throws IOException {
final IdleShutdown idleShutdown = m.mock(IdleShutdown.class);

m.checking(new Expectations() {{
allowing(fileUtils).readFile(new File("/var/lib/waagent/ovf-env.xml"));
one(fileUtils).readFile(new File("/var/lib/waagent/ovf-env.xml"));
will(returnValue(StringUtil.EMPTY));

allowing(fileUtils).readFile(new File("/var/lib/waagent/SharedConfig.xml"));
one(fileUtils).readFile(new File("/var/lib/waagent/SharedConfig.xml"));
will(returnValue(StringUtil.EMPTY));
}});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,22 @@ public void testProcessWindowsConfig() throws IOException {
final String drive = System.getenv("SystemDrive");

m.checking(new Expectations() {{
allowing(fileUtils).listFiles(new File(drive + "\\WindowsAzure\\Config"));
one(fileUtils).listFiles(new File(drive + "\\WindowsAzure\\Config"));
will(returnValue(new File[]{new File("src/test/resources/SharedConfig.xml")}));

allowing(fileUtils).getCreationDate(with(any(File.class)));
one(fileUtils).getCreationDate(with(any(File.class)));
will(returnValue(1L));

allowing(agentConfiguration).setOwnPort(9090);
allowing(agentConfiguration).setName("paksvvm-53eb78da");
allowing(agentConfiguration).addAlternativeAgentAddress("191.233.107.5");
allowing(agentConfiguration).setServerUrl("https://teamcityserver.url");
allowing(agentConfiguration).addConfigurationParameter(AzurePropertiesNames.INSTANCE_NAME, "paksvvm-53eb78da");
allowing(agentConfiguration).addConfigurationParameter("system.cloud.profile_id", "arm-1");
allowing(agentConfiguration).addConfigurationParameter("teamcity.cloud.instance.hash", "C7PfiVOkdPi6Ak5cAO8Iq5NWPtHbO14q");
one(agentConfiguration).setOwnPort(9090);
one(agentConfiguration).addAlternativeAgentAddress("191.233.107.5");
one(agentConfiguration).setServerUrl("https://teamcityserver.url");
one(agentConfiguration).addConfigurationParameter("system.cloud.profile_id", "arm-1");
one(agentConfiguration).addConfigurationParameter("teamcity.cloud.instance.hash", "C7PfiVOkdPi6Ak5cAO8Iq5NWPtHbO14q");

allowing(fileUtils).readFile(new File(drive + "\\AzureData\\CustomData.bin"));
one(fileUtils).readFile(new File(drive + "\\AzureData\\CustomData.bin"));
will(returnValue(FileUtil.readText(new File("src/test/resources/CustomData.bin"))));

allowing(idleShutdown).setIdleTime(2400000L);
one(idleShutdown).setIdleTime(2400000L);
}});

WindowsConfigReader configReader = new WindowsConfigReader(agentConfiguration, idleShutdown, fileUtils);
Expand All @@ -67,22 +65,20 @@ public void testProcessWindowsConfigWithoutEndpoints() throws IOException {
final String drive = System.getenv("SystemDrive");

m.checking(new Expectations() {{
allowing(fileUtils).listFiles(new File(drive + "\\WindowsAzure\\Config"));
one(fileUtils).listFiles(new File(drive + "\\WindowsAzure\\Config"));
will(returnValue(new File[]{new File("src/test/resources/windows-config.xml")}));

allowing(fileUtils).getCreationDate(with(any(File.class)));
one(fileUtils).getCreationDate(with(any(File.class)));
will(returnValue(1L));

allowing(agentConfiguration).setName("tc-win-agent");
allowing(agentConfiguration).setServerUrl("https://teamcityserver.url");
allowing(agentConfiguration).addConfigurationParameter(AzurePropertiesNames.INSTANCE_NAME, "tc-win-agent");
allowing(agentConfiguration).addConfigurationParameter("system.cloud.profile_id", "arm-1");
allowing(agentConfiguration).addConfigurationParameter("teamcity.cloud.instance.hash", "C7PfiVOkdPi6Ak5cAO8Iq5NWPtHbO14q");
one(agentConfiguration).setServerUrl("https://teamcityserver.url");
one(agentConfiguration).addConfigurationParameter("system.cloud.profile_id", "arm-1");
one(agentConfiguration).addConfigurationParameter("teamcity.cloud.instance.hash", "C7PfiVOkdPi6Ak5cAO8Iq5NWPtHbO14q");

allowing(fileUtils).readFile(new File(drive + "\\AzureData\\CustomData.bin"));
one(fileUtils).readFile(new File(drive + "\\AzureData\\CustomData.bin"));
will(returnValue(FileUtil.readText(new File("src/test/resources/CustomData.bin"))));

allowing(idleShutdown).setIdleTime(2400000L);
one(idleShutdown).setIdleTime(2400000L);
}});

WindowsConfigReader configReader = new WindowsConfigReader(agentConfiguration, idleShutdown, fileUtils);
Expand All @@ -102,14 +98,14 @@ public void testDisableIntegrationWithoutCustomDataFile() throws IOException {
final String drive = System.getenv("SystemDrive");

m.checking(new Expectations() {{
allowing(fileUtils).listFiles(new File(drive + "\\WindowsAzure\\Config"));
one(fileUtils).readFile(new File(drive + "\\AzureData\\CustomData.bin"));
will(returnValue(StringUtil.EMPTY));

one(fileUtils).listFiles(new File(drive + "\\WindowsAzure\\Config"));
will(returnValue(new File[]{new File("src/test/resources/windows-config.xml")}));

allowing(fileUtils).getCreationDate(with(any(File.class)));
one(fileUtils).getCreationDate(with(any(File.class)));
will(returnValue(1L));

allowing(fileUtils).readFile(new File(drive + "\\AzureData\\CustomData.bin"));
will(returnValue(StringUtil.EMPTY));
}});

WindowsConfigReader configReader = new WindowsConfigReader(agentConfiguration, idleShutdown, fileUtils);
Expand All @@ -129,10 +125,10 @@ public void testDisableIntegrationWithoutPropertiesFile() throws IOException {
final String drive = System.getenv("SystemDrive");

m.checking(new Expectations() {{
allowing(fileUtils).readFile(new File(drive + "\\AzureData\\CustomData.bin"));
one(fileUtils).readFile(new File(drive + "\\AzureData\\CustomData.bin"));
will(returnValue("data"));

allowing(fileUtils).listFiles(new File(drive + "\\WindowsAzure\\Config"));
one(fileUtils).listFiles(new File(drive + "\\WindowsAzure\\Config"));
will(returnValue(new File[]{}));
}});

Expand Down
6 changes: 6 additions & 0 deletions plugin-azure-agent/src/test/resources/ovf-env2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<ns0:Environment xmlns:ns0="http://schemas.dmtf.org/ovf/environment/1" xmlns:ns1="http://schemas.microsoft.com/windowsazure" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<ns1:ProvisioningSection><ns1:Version>1.0</ns1:Version><ns1:LinuxProvisioningConfigurationSet><ns1:ConfigurationSetType>LinuxProvisioningConfiguration</ns1:ConfigurationSetType><ns1:HostName>tc-lin9</ns1:HostName><ns1:UserName>azureuser</ns1:UserName><ns1:UserPassword>REDACTED</ns1:UserPassword><ns1:DisableSshPasswordAuthentication>false</ns1:DisableSshPasswordAuthentication><ns1:CustomData>UEQ5NGJXd2dkbVZ5YzJsdmJqMGlNUzR3SWlCbGJtTnZaR2x1WnowaVZWUkdMVGdpUHo0TkNqeGpiRzkxWkMxcGJuTjBZVzVqWlMxa1lYUmhQZzBLSUNBOGEyVjVMWFpoYkhWbFBnMEtJQ0FnSUR4bGJuUnllU0JyWlhrOUltRm5aVzUwTFc1aGJXVWlQandoVzBORVFWUkJXM0JoYTNOMmRtMHROVE5sWWpjNFpHRmRYVDQ4TDJWdWRISjVQZzBLSUNBZ0lEeGxiblJ5ZVNCclpYazlJbUYxZEdndGRHOXJaVzRpSUM4K0RRb2dJQ0FnUEdWdWRISjVJR3RsZVQwaWMyVnlkbVZ5TFdGa1pISmxjM01pUGp3aFcwTkVRVlJCVzJoMGRIQTZMeTkwWXkxemNuWXVZMnh2ZFdSaGNIQXVibVYwT2pneE1URmRYVDQ4TDJWdWRISjVQZzBLSUNBZ0lEeGxiblJ5ZVNCclpYazlJbkJ5YjJacGJHVWlQandoVzBORVFWUkJXM0J5YjJacGJHVWdKMEZTVFNCd2NtOW1hV3hsSjN0cFpEMWpjREY5WFYwK1BDOWxiblJ5ZVQ0TkNpQWdJQ0E4Wlc1MGNua2dhMlY1UFNKcFpHeGxMWFJwYldWdmRYUWlQakkwTURBd01EQThMMlZ1ZEhKNVBnMEtJQ0E4TDJ0bGVTMTJZV3gxWlQ0TkNpQWdQR0ZuWlc1MExXTnZibVpwWjNWeVlYUnBiMjR0Y0dGeVlXMWxkR1Z5Y3o0TkNpQWdJQ0E4Wlc1MGNua2dhMlY1UFNKemVYTjBaVzB1WTJ4dmRXUXVjSEp2Wm1sc1pWOXBaQ0krUENGYlEwUkJWRUZiWTNBeFhWMCtQQzlsYm5SeWVUNE5DaUFnSUNBOFpXNTBjbmtnYTJWNVBTSjBaV0Z0WTJsMGVTNWpiRzkxWkM1cGJuTjBZVzVqWlM1b1lYTm9JajQ4SVZ0RFJFRlVRVnRPZURVd1RrRm1lbVZ2Ykdwb00ybEtaamMzYW5aMFkya3hRbE5YZEdGYU1sMWRQand2Wlc1MGNuaytEUW9nSUR3dllXZGxiblF0WTI5dVptbG5kWEpoZEdsdmJpMXdZWEpoYldWMFpYSnpQZzBLUEM5amJHOTFaQzFwYm5OMFlXNWpaUzFrWVhSaFBnMEs=</ns1:CustomData></ns1:LinuxProvisioningConfigurationSet></ns1:ProvisioningSection>

<ns1:PlatformSettingsSection><ns1:Version>1.0</ns1:Version><ns1:PlatformSettings><ns1:KmsServerHostname>kms.core.windows.net</ns1:KmsServerHostname><ns1:ProvisionGuestAgent>false</ns1:ProvisionGuestAgent><ns1:GuestAgentPackageName xsi:nil="true" /><ns1:RetainWindowsPEPassInUnattend>false</ns1:RetainWindowsPEPassInUnattend><ns1:RetainOfflineServicingPassInUnattend>false</ns1:RetainOfflineServicingPassInUnattend></ns1:PlatformSettings></ns1:PlatformSettingsSection>
</ns0:Environment>

0 comments on commit b98f134

Please sign in to comment.