Merge pull request #66 from clguimanMSFT/windows-storage-name

Make Windows agents deployment easier
This commit is contained in:
Arjun Roy Chaudhuri 2016-11-21 11:23:52 -08:00 committed by GitHub
commit 82b17395d4
3 changed files with 79 additions and 34 deletions

View File

@ -41,6 +41,7 @@ import org.kohsuke.stapler.QueryParameter;
import com.microsoft.azure.util.AzureUtil;
import com.microsoft.azure.util.Constants;
import com.microsoft.azure.util.FailureStage;
import com.microsoft.windowsazure.core.utils.Base64;
import hudson.Extension;
import hudson.RelativePath;
@ -55,6 +56,7 @@ import hudson.security.ACL;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import java.net.URISyntaxException;
import java.security.MessageDigest;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
@ -129,14 +131,14 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
private String templateStatusDetails;
public transient AzureVMCloud azureCloud;
private transient AzureVMCloud azureCloud;
private transient Set<LabelAtom> labelDataSet;
private boolean templateVerified;
private boolean executeInitScriptAsRoot;
private boolean doNotUseMachineIfInitFails;
@DataBoundConstructor
@ -176,9 +178,10 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
this.location = location;
this.virtualMachineSize = virtualMachineSize;
this.storageAccountName = storageAccountName;
if (StringUtils.isBlank(noOfParallelJobs) || !noOfParallelJobs.matches(Constants.REG_EX_DIGIT)
|| noOfParallelJobs.
trim().equals("0")) {
trim().equals("0")) {
this.noOfParallelJobs = 1;
} else {
this.noOfParallelJobs = Integer.parseInt(noOfParallelJobs);
@ -211,7 +214,7 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
// Reset the template verification status.
this.templateVerified = false;
// Forms data which is not persisted
readResolve();
}
@ -321,6 +324,13 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
return azureCloud;
}
public void setAzureCloud(AzureVMCloud cloud) {
azureCloud = cloud;
if (StringUtils.isBlank(storageAccountName)) {
storageAccountName = AzureVMAgentTemplate.GenerateUniqueStorageAccountName(azureCloud.getResourceGroupName());
}
}
public String getTemplateName() {
return templateName;
}
@ -338,24 +348,27 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
}
/**
* Returns true if this template is disabled and cannot be used,
* false otherwise.
* Returns true if this template is disabled and cannot be used, false
* otherwise.
*
* @return True/false
*/
public boolean isTemplateDisabled() {
return this.templateDisabled;
}
/**
* Is the template set up and verified?
*
* @return True if the template is set up and verified, false otherwise.
*/
public boolean isTemplateVerified() {
return templateVerified;
}
/**
* Set the template verification status
*
* @param isValid True for verified + valid, false otherwise.
*/
public void setTemplateVerified(boolean isValid) {
@ -369,16 +382,16 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
public void setTemplateStatusDetails(String templateStatusDetails) {
this.templateStatusDetails = templateStatusDetails;
}
public String getResourceGroupName() {
// Allow overriding?
return getAzureCloud().getResourceGroupName();
}
public boolean getExecuteInitScriptAsRoot() {
return executeInitScriptAsRoot;
}
public void setExecuteInitScriptAsRoot(boolean executeAsRoot) {
executeInitScriptAsRoot = executeAsRoot;
}
@ -403,6 +416,7 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
/**
* Provision new agents using this template.
*
* @param listener
* @param numberOfAgents Number of agents to provision
* @return New deployment info if the provisioning was successful.
@ -411,9 +425,11 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
public AzureVMDeploymentInfo provisionAgents(final TaskListener listener, int numberOfAgents) throws Exception {
return AzureVMManagementServiceDelegate.createDeployment(this, numberOfAgents);
}
/**
* If provisioning failed, handle the status and queue the template for verification.
* If provisioning failed, handle the status and queue the template for
* verification.
*
* @param message Failure message
* @param failureStep Stage that failure occurred
*/
@ -428,8 +444,9 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
/**
* Verify that this template is correct and can be allocated.
*
* @return Empty list if this template is valid, list of errors otherwise
* @throws Exception
* @throws Exception
*/
public List<String> verifyTemplate() throws Exception {
return AzureVMManagementServiceDelegate.verifyTemplate(
@ -481,7 +498,7 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
return model;
}
public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Item owner) {
// when configuring the job, you only want those credentials that are available to ACL.SYSTEM selectable
// as we cannot select from a user's credentials unless they are the only user submitting the build
@ -500,13 +517,12 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
@RelativePath("..") @QueryParameter final String serviceManagementURL)
throws IOException, ServletException {
ListBoxModel model = new ListBoxModel();
Map<String, String> locations = AzureVMManagementServiceDelegate.getVirtualMachineLocations(serviceManagementURL);
// This map contains display name -> actual location name. We
// need the actual location name later, but just grab the keys of
// the map for the model.
for (String location : locations.keySet()) {
model.add(location);
}
@ -546,12 +562,13 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
}
/**
* Check the template's name. Name must conform to restrictions on VM
* Check the template's name. Name must conform to restrictions on VM
* naming
*
* @param value Current name
* @param templateDisabled Is the template disabled
* @param osType OS type
* @return
* @return
*/
public FormValidation doCheckTemplateName(
@QueryParameter final String value, @QueryParameter final boolean templateDisabled,
@ -562,15 +579,15 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
if (!AzureUtil.isValidTemplateName(value)) {
errors.add(FormValidation.error(Messages.Azure_GC_Template_Name_Not_Valid()));
}
if (templateDisabled) {
errors.add(FormValidation.warning(Messages.Azure_GC_TemplateStatus_Warn_Msg()));
}
if (errors.size() > 0) {
return FormValidation.aggregate(errors);
}
return FormValidation.ok();
}
@ -672,7 +689,7 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
+ "subnetName: {22};\n\t"
+ "retentionTimeInMin: {23};\n\t"
+ "jvmOptions: {24};",
new Object[] {
new Object[]{
servicePrincipal.subscriptionId.getPlainText(),
(StringUtils.isNotBlank(servicePrincipal.clientId.getPlainText()) ? "********" : null),
(StringUtils.isNotBlank(servicePrincipal.clientSecret.getPlainText()) ? "********" : null),
@ -700,12 +717,11 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
// First validate the subscription info. If it is not correct,
// then we can't validate the
String result = AzureVMManagementServiceDelegate.verifyConfiguration(servicePrincipal, resourceGroupName);
if (!result.equals(Constants.OP_SUCCESS)) {
return FormValidation.error(result);
}
final List<String> errors = AzureVMManagementServiceDelegate.verifyTemplate(
servicePrincipal,
templateName,
@ -752,4 +768,18 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
public void setVirtualMachineDetails(final AzureVMAgent agent) throws Exception {
AzureVMManagementServiceDelegate.setVirtualMachineDetails(agent, this);
}
public static String GenerateUniqueStorageAccountName(final String resourceGroupName) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
String uid = Base64.encode(md.digest(resourceGroupName.getBytes()));
uid = uid.substring(0, 22);
uid = uid.toLowerCase();
uid = uid.replaceAll("[^a-z0-9]","a");
return "jn" + uid;
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Could not genetare UID from the resource group name. Will fallback on using the resource group name.", e);
return "";
}
}
}

View File

@ -156,7 +156,7 @@ public class AzureVMCloud extends Cloud {
private Object readResolve() {
for (AzureVMAgentTemplate template : instTemplates) {
template.azureCloud = this;
template.setAzureCloud(this);
}
return this;
}

View File

@ -75,6 +75,9 @@ import com.microsoft.windowsazure.Configuration;
import com.microsoft.windowsazure.exception.ServiceException;
import com.microsoft.azure.exceptions.AzureCloudException;
import com.microsoft.azure.exceptions.UnrecoverableCloudException;
import com.microsoft.azure.management.resources.models.ResourceGroupCreateOrUpdateResult;
import com.microsoft.azure.management.storage.models.AccountType;
import com.microsoft.azure.management.storage.models.StorageAccountCreateParameters;
import com.microsoft.azure.retry.ExponentialRetryStrategy;
import com.microsoft.azure.retry.NoRetryStrategy;
import com.microsoft.azure.util.AzureCredentials;
@ -329,18 +332,30 @@ public class AzureVMManagementServiceDelegate {
*/
private static String uploadCustomScript(final AzureVMAgentTemplate template, final String targetScriptName) throws Exception {
Configuration config = ServiceDelegateHelper.getConfiguration(template);
StorageManagementClient client = ServiceDelegateHelper.getStorageManagementClient(config);
// Get the storage account name and key
String targetStorageAccount = template.getStorageAccountName();
String resourceGroupName = template.getResourceGroupName();
String storageAccountKey = client.getStorageAccountsOperations().listKeys(resourceGroupName, targetStorageAccount)
String location = template.getLocation();
//make sure the resource group and storage account exist
final ResourceManagementClient rmClient = ServiceDelegateHelper.getResourceManagementClient(config);
final StorageManagementClient storageClient = ServiceDelegateHelper.getStorageManagementClient(config);
rmClient.getResourceGroupsOperations().createOrUpdate(resourceGroupName, new ResourceGroup(location));
StorageAccountCreateParameters createParams = new StorageAccountCreateParameters();
createParams.setLocation(location);
createParams.setAccountType(AccountType.StandardLRS);
storageClient.getStorageAccountsOperations().create(resourceGroupName, targetStorageAccount, createParams);
// Get the storage account name and key
String storageAccountKey = storageClient.getStorageAccountsOperations().listKeys(resourceGroupName, targetStorageAccount)
.getStorageAccountKeys().getKey1();
String scriptText = template.getInitScript();
String blobURL = StorageServiceDelegate.uploadFileToStorage(
config, targetStorageAccount, storageAccountKey,
client.getBaseUri().toString(), resourceGroupName, Constants.CONFIG_CONTAINER_NAME,
storageClient.getBaseUri().toString(), resourceGroupName, Constants.CONFIG_CONTAINER_NAME,
targetScriptName, scriptText.getBytes("UTF-8"));
return blobURL;
}