Skip to content

Commit

Permalink
Add option to deploy VM agents without a public IP [FIXED JENKINS-40620]
Browse files Browse the repository at this point in the history
  • Loading branch information
clguiman committed Apr 6, 2017
1 parent 957d2b2 commit 62c2590
Show file tree
Hide file tree
Showing 13 changed files with 304 additions and 173 deletions.
Expand Up @@ -56,7 +56,6 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.Map;
import java.util.logging.Level;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.lang.StringUtils;
Expand Down Expand Up @@ -126,6 +125,8 @@ public enum ImageReferenceType {

private String subnetName;

private boolean usePrivateIP;

private final String jvmOptions;

// Indicates whether the template is disabled.
Expand Down Expand Up @@ -167,6 +168,7 @@ public AzureVMAgentTemplate(
final String credentialsId,
final String virtualNetworkName,
final String subnetName,
final boolean usePrivateIP,
final String agentWorkspace,
final String jvmOptions,
final String retentionTimeInMin,
Expand Down Expand Up @@ -203,6 +205,7 @@ public AzureVMAgentTemplate(
this.credentialsId = credentialsId;
this.virtualNetworkName = virtualNetworkName;
this.subnetName = subnetName;
this.usePrivateIP = usePrivateIP;
this.agentWorkspace = agentWorkspace;
this.jvmOptions = jvmOptions;
this.executeInitScriptAsRoot = executeInitScriptAsRoot;
Expand Down Expand Up @@ -333,6 +336,10 @@ public String getSubnetName() {
public void setSubnetName(String subnetName) {
this.subnetName = subnetName;
}

public boolean getUsePrivateIP() {
return usePrivateIP;
}

public String getAgentWorkspace() {
return agentWorkspace;
Expand Down Expand Up @@ -475,8 +482,7 @@ public void handleTemplateProvisioningFailure(final String message, final Failur
* @throws Exception
*/
public List<String> verifyTemplate() throws Exception {
return AzureVMManagementServiceDelegate.verifyTemplate(
azureCloud.getServicePrincipal(),
return AzureVMManagementServiceDelegate.verifyTemplate(azureCloud.getServicePrincipal(),
templateName,
labels,
location,
Expand All @@ -498,7 +504,8 @@ public List<String> verifyTemplate() throws Exception {
retentionTimeInMin + "",
jvmOptions,
getResourceGroupName(),
true);
true,
usePrivateIP);
}

@Extension
Expand Down Expand Up @@ -695,6 +702,7 @@ public FormValidation doVerifyConfiguration(
@QueryParameter String credentialsId,
@QueryParameter String virtualNetworkName,
@QueryParameter String subnetName,
@QueryParameter boolean usePrivateIP,
@QueryParameter String retentionTimeInMin,
@QueryParameter String jvmOptions,
@QueryParameter String imageReferenceType) {
Expand Down Expand Up @@ -736,8 +744,9 @@ public FormValidation doVerifyConfiguration(
+ "credentialsId: {19};\n\t"
+ "virtualNetworkName: {20};\n\t"
+ "subnetName: {21};\n\t"
+ "retentionTimeInMin: {22};\n\t"
+ "jvmOptions: {23};",
+ "privateIP: {22};\n\t"
+ "retentionTimeInMin: {23};\n\t"
+ "jvmOptions: {24};",
new Object[]{
servicePrincipal.getSubscriptionId(),
(StringUtils.isNotBlank(servicePrincipal.getClientId()) ? "********" : null),
Expand All @@ -761,6 +770,7 @@ public FormValidation doVerifyConfiguration(
credentialsId,
virtualNetworkName,
subnetName,
usePrivateIP,
retentionTimeInMin,
jvmOptions});

Expand Down Expand Up @@ -795,7 +805,8 @@ public FormValidation doVerifyConfiguration(
retentionTimeInMin,
jvmOptions,
resourceGroupName,
false);
false,
usePrivateIP);

if (errors.size() > 0) {
StringBuilder errorString = new StringBuilder(Messages.Azure_GC_Template_Error_List()).append("\n");
Expand Down
Expand Up @@ -52,6 +52,7 @@
import com.microsoft.azure.management.compute.VirtualMachineSize;
import com.microsoft.azure.management.compute.VirtualMachineSku;
import com.microsoft.azure.management.network.Network;
import com.microsoft.azure.management.network.PublicIpAddress;
import com.microsoft.azure.management.resources.DeploymentMode;
import com.microsoft.azure.management.storage.SkuName;
import com.microsoft.azure.management.resources.Provider;
Expand Down Expand Up @@ -107,6 +108,8 @@ public class AzureVMManagementServiceDelegate {

private static final String VIRTUAL_NETWORK_TEMPLATE_FRAGMENT_FILENAME = "/virtualNetworkFragment.json";

private static final String PUBLIC_IP_FRAGMENT_FILENAME = "/publicIPFragment.json";

private static final String IMAGE_CUSTOM_REFERENCE = "custom";

private static final Map<String, List<String>> AVAILABLE_ROLE_SIZES = getAvailableRoleSizes();
Expand Down Expand Up @@ -140,7 +143,6 @@ public static AzureVMDeploymentInfo createDeployment(final AzureVMAgentTemplate
throws AzureCloudException, IOException {

InputStream embeddedTemplate = null;
InputStream fragmentStream = null;
try {
LOGGER.log(Level.INFO,
"AzureVMManagementServiceDelegate: createDeployment: Initializing deployment for agentTemplate {0}",
Expand Down Expand Up @@ -285,38 +287,13 @@ public static AzureVMDeploymentInfo createDeployment(final AzureVMAgentTemplate
ObjectNode.class.cast(tmp.get("variables")).put("virtualNetworkName", template.getVirtualNetworkName());
ObjectNode.class.cast(tmp.get("variables")).put("subnetName", template.getSubnetName());
} else {
// Add the definition of the vnet and subnet into the template
final String virtualNetworkName = Constants.DEFAULT_VNET_NAME;
final String subnetName = Constants.DEFAULT_SUBNET_NAME;
ObjectNode.class.cast(tmp.get("variables")).put("virtualNetworkName", virtualNetworkName);
ObjectNode.class.cast(tmp.get("variables")).put("subnetName", subnetName);

// Read the vnet fragment
fragmentStream = AzureVMManagementServiceDelegate.class.getResourceAsStream(VIRTUAL_NETWORK_TEMPLATE_FRAGMENT_FILENAME);

final JsonNode virtualNetworkFragment = mapper.readTree(fragmentStream);
// Add the virtual network fragment
ArrayNode.class.cast(tmp.get("resources")).add(virtualNetworkFragment);

// Because we created/updated this in the template, we need to add the appropriate
// dependsOn node to the networkInterface
// Microsoft.Network/virtualNetworks/<vnet name>
// Find the network interfaces node
ArrayNode resourcesNodes = ArrayNode.class.cast(tmp.get("resources"));
Iterator<JsonNode> resourcesNodesIter = resourcesNodes.elements();
while (resourcesNodesIter.hasNext()) {
JsonNode resourcesNode = resourcesNodesIter.next();
JsonNode typeNode = resourcesNode.get("type");
if (typeNode == null || !typeNode.asText().equals("Microsoft.Network/networkInterfaces")) {
continue;
}
// Find the dependsOn node
ArrayNode dependsOnNode = ArrayNode.class.cast(resourcesNode.get("dependsOn"));
// Add to the depends on node.
dependsOnNode.add("[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]");
break;
}
AddDefaultVNetResourceNode(tmp, mapper);
}

if (!template.getUsePrivateIP()) {
AddPublicIPResourceNode(tmp, mapper);
}

// Register the deployment for cleanup
deploymentRegistrar.registerDeployment(template.getAzureCloud().name, template.getResourceGroupName(), deploymentName);
// Create the deployment
Expand All @@ -336,8 +313,104 @@ public static AzureVMDeploymentInfo createDeployment(final AzureVMAgentTemplate
finally {
if (embeddedTemplate != null)
embeddedTemplate.close();
if (fragmentStream != null)
}
}

private static void AddPublicIPResourceNode(
final JsonNode template,
final ObjectMapper mapper) throws IOException {

final String ipName = "variables('vmName'), copyIndex(), 'IPName'";
try (InputStream fragmentStream = AzureVMManagementServiceDelegate.class.getResourceAsStream(PUBLIC_IP_FRAGMENT_FILENAME)) {

final JsonNode publicIPFragment = mapper.readTree(fragmentStream);
// Add the virtual network fragment
ArrayNode.class.cast(template.get("resources")).add(publicIPFragment);

// Because we created/updated this in the template, we need to add the appropriate
// dependsOn node to the networkInterface and the ipConfigurations properties
// "[concat('Microsoft.Network/publicIPAddresses/', variables('vmName'), copyIndex(), 'IPName')]"
// Find the network interfaces node
ArrayNode resourcesNodes = ArrayNode.class.cast(template.get("resources"));
Iterator<JsonNode> resourcesNodesIter = resourcesNodes.elements();
while (resourcesNodesIter.hasNext()) {
JsonNode resourcesNode = resourcesNodesIter.next();
JsonNode typeNode = resourcesNode.get("type");
if (typeNode == null || !typeNode.asText().equals("Microsoft.Network/networkInterfaces")) {
continue;
}
// Find the dependsOn node
ArrayNode dependsOnNode = ArrayNode.class.cast(resourcesNode.get("dependsOn"));
// Add to the depends on node.
dependsOnNode.add("[concat('Microsoft.Network/publicIPAddresses/'," + ipName + ")]");

//Find the ipConfigurations/ipconfig1 node
ArrayNode ipConfigurationsNode = ArrayNode.class.cast(resourcesNode.get("properties").get("ipConfigurations"));
Iterator<JsonNode> ipConfigNodeIter = ipConfigurationsNode.elements();
while (ipConfigNodeIter.hasNext()) {
JsonNode ipConfigNode = ipConfigNodeIter.next();
JsonNode nameNode = ipConfigNode.get("name");
if (nameNode == null || !nameNode.asText().equals("ipconfig1")) {
continue;
}
//find the properties node
ObjectNode propertiesNode = ObjectNode.class.cast(ipConfigNode.get("properties"));
//add the publicIPAddress node
ObjectNode publicIPIdNode = mapper.createObjectNode();
publicIPIdNode.put("id", "[resourceId('Microsoft.Network/publicIPAddresses', concat("
+ ipName
+ "))]");
// propertiesNode.putObject("publicIPAddress").put
propertiesNode.set("publicIPAddress", publicIPIdNode);
break;
}
break;
}
}
}

private static void AddDefaultVNetResourceNode(
final JsonNode template,
final ObjectMapper mapper) throws IOException {
InputStream fragmentStream = null;
try {
// Add the definition of the vnet and subnet into the template
final String virtualNetworkName = Constants.DEFAULT_VNET_NAME;
final String subnetName = Constants.DEFAULT_SUBNET_NAME;
ObjectNode.class.cast(template.get("variables")).put("virtualNetworkName", virtualNetworkName);
ObjectNode.class.cast(template.get("variables")).put("subnetName", subnetName);

// Read the vnet fragment
fragmentStream = AzureVMManagementServiceDelegate.class.getResourceAsStream(VIRTUAL_NETWORK_TEMPLATE_FRAGMENT_FILENAME);

final JsonNode virtualNetworkFragment = mapper.readTree(fragmentStream);
// Add the virtual network fragment
ArrayNode.class.cast(template.get("resources")).add(virtualNetworkFragment);

// Because we created/updated this in the template, we need to add the appropriate
// dependsOn node to the networkInterface
// Microsoft.Network/virtualNetworks/<vnet name>
// Find the network interfaces node
ArrayNode resourcesNodes = ArrayNode.class.cast(template.get("resources"));
Iterator<JsonNode> resourcesNodesIter = resourcesNodes.elements();
while (resourcesNodesIter.hasNext()) {
JsonNode resourcesNode = resourcesNodesIter.next();
JsonNode typeNode = resourcesNode.get("type");
if (typeNode == null || !typeNode.asText().equals("Microsoft.Network/networkInterfaces")) {
continue;
}
// Find the dependsOn node
ArrayNode dependsOnNode = ArrayNode.class.cast(resourcesNode.get("dependsOn"));
// Add to the depends on node.
dependsOnNode.add("[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]");
break;
}
} catch (Exception e) {
throw e;
} finally {
if (fragmentStream != null) {
fragmentStream.close();
}
}
}

Expand Down Expand Up @@ -385,7 +458,15 @@ public static void setVirtualMachineDetails(
VirtualMachine vm = azureClient.virtualMachines().getByGroup(template.getResourceGroupName(), azureAgent.getNodeName());

// Getting the first virtual IP
azureAgent.setPublicDNSName(vm.getPrimaryPublicIpAddress().fqdn());
final PublicIpAddress publicIP = vm.getPrimaryPublicIpAddress();
String fqdn = "";
if (publicIP == null) {
fqdn = vm.getPrimaryNetworkInterface().primaryPrivateIp();
LOGGER.log(Level.INFO, "The Azure agent doesn't have a public IP. Will use the private IP");
} else {
fqdn = publicIP.fqdn();
}
azureAgent.setPublicDNSName(fqdn);
azureAgent.setSshPort(Constants.DEFAULT_SSH_PORT);

LOGGER.log(Level.INFO, "Azure agent details:\nnodeName{0}\nadminUserName={1}\nshutdownOnIdle={2}\nretentionTimeInMin={3}\nlabels={4}",
Expand Down Expand Up @@ -1012,6 +1093,7 @@ private static String getLocationName(String location) {
* @param virtualMachineSize
* @param storageAccountName
* @param noOfParallelJobs
* @param referenceType
* @param isCustomReferenceUsed
* @param image
* @param osType
Expand All @@ -1028,6 +1110,7 @@ private static String getLocationName(String location) {
* @param jvmOptions
* @param returnOnSingleError
* @param resourceGroupName
* @param usePrivateIP
* @return
*/
public static List<String> verifyTemplate(
Expand All @@ -1053,7 +1136,8 @@ public static List<String> verifyTemplate(
final String retentionTimeInMin,
final String jvmOptions,
final String resourceGroupName,
final boolean returnOnSingleError) {
final boolean returnOnSingleError,
final boolean usePrivateIP) {

List<String> errors = new ArrayList<String>();

Expand Down Expand Up @@ -1122,7 +1206,8 @@ public static List<String> verifyTemplate(
virtualNetworkName,
subnetName,
resourceGroupName,
errors
errors,
usePrivateIP
);

} catch (Exception e) {
Expand All @@ -1146,7 +1231,8 @@ private static void verifyTemplateAsync(
final String virtualNetworkName,
final String subnetName,
final String resourceGroupName,
final List<String> errors) {
final List<String> errors,
final boolean usePrivateIP) {

List<Callable<String>> verificationTaskList = new ArrayList<Callable<String>>();

Expand All @@ -1155,7 +1241,7 @@ private static void verifyTemplateAsync(

@Override
public String call() throws Exception {
return verifyVirtualNetwork(servicePrincipal, virtualNetworkName, subnetName, resourceGroupName);
return verifyVirtualNetwork(servicePrincipal, virtualNetworkName, subnetName, usePrivateIP, resourceGroupName);
}
};
verificationTaskList.add(callVerifyVirtualNetwork);
Expand Down Expand Up @@ -1236,18 +1322,21 @@ public static String verifyVirtualNetwork(
final ServicePrincipal servicePrincipal,
final String virtualNetworkName,
final String subnetName,
final boolean usePrivateIP,
final String resourceGroupName) {
if (StringUtils.isNotBlank(virtualNetworkName)) {
Network virtualNetwork = getVirtualNetwork(servicePrincipal, virtualNetworkName, resourceGroupName);
if (virtualNetwork == null) {
return Messages.Azure_GC_Template_VirtualNetwork_NotFound(virtualNetworkName);
}

if (StringUtils.isNotBlank(subnetName)) {
if (StringUtils.isBlank(subnetName)) {
return Messages.Azure_GC_Template_subnet_Empty();
} else {
if (virtualNetwork.subnets().get(subnetName) == null)
return Messages.Azure_GC_Template_subnet_NotFound(subnetName);
}
} else if (StringUtils.isNotBlank(subnetName)) {
} else if (StringUtils.isNotBlank(subnetName) || usePrivateIP) {
return Messages.Azure_GC_Template_VirtualNetwork_Null_Or_Empty();
}
return Constants.OP_SUCCESS;
Expand Down
Expand Up @@ -97,6 +97,10 @@
<f:textbox />
</f:entry>

<f:entry title="${%Use_Private_Ip}" field="usePrivateIP" help="/plugin/azure-vm-agents/help-agentPrivateIp.html">
<f:checkbox default="false"/>
</f:entry>

<f:entry title="${%Agent_Workspace}" field="agentWorkspace" help="/plugin/azure-vm-agents/help-agentWorkspace.html">
<f:textbox />
</f:entry>
Expand All @@ -123,6 +127,6 @@
</div>
</f:entry>
<f:validateButton title="${%Verify_Template}" progress="${%Verifying_Template_MSG}" method="verifyConfiguration"
with="azureCredentialsId,resourceGroupName,maxVirtualMachinesLimit,deploymentTimeout,templateName,labels,location,virtualMachineSize,storageAccountName,noOfParallelJobs,image,osType,imagePublisher,imageOffer,imageSku,imageVersion,agentLaunchMethod,initScript,credentialsId,virtualNetworkName,subnetName,retentionTimeInMin,jvmOptions,imageReferenceType" />
with="azureCredentialsId,resourceGroupName,maxVirtualMachinesLimit,deploymentTimeout,templateName,labels,location,virtualMachineSize,storageAccountName,noOfParallelJobs,image,osType,imagePublisher,imageOffer,imageSku,imageVersion,agentLaunchMethod,initScript,credentialsId,virtualNetworkName,subnetName,usePrivateIP,retentionTimeInMin,jvmOptions,imageReferenceType" />
</table>
</j:jelly>

0 comments on commit 62c2590

Please sign in to comment.