Merge pull request #65 from clguimanMSFT/credentials-in-store
Credentials in store
This commit is contained in:
commit
baa1d08e78
11
pom.xml
11
pom.xml
|
@ -116,6 +116,17 @@
|
|||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins</groupId>
|
||||
<artifactId>credentials</artifactId>
|
||||
<version>1.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins</groupId>
|
||||
<artifactId>plain-credentials</artifactId>
|
||||
<version>1.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<scm>
|
||||
|
|
|
@ -28,6 +28,7 @@ import com.microsoft.azure.util.Constants;
|
|||
import com.microsoft.azure.util.CleanUpAction;
|
||||
import com.microsoft.azure.util.FailureStage;
|
||||
import com.microsoft.azure.remote.AzureVMAgentSSHLauncher;
|
||||
import com.microsoft.azure.util.AzureCredentials;
|
||||
|
||||
import hudson.Extension;
|
||||
import hudson.model.TaskListener;
|
||||
|
@ -44,18 +45,20 @@ import org.jvnet.localizer.Localizable;
|
|||
|
||||
public class AzureVMAgent extends AbstractCloudSlave {
|
||||
|
||||
private static final long serialVersionUID = -760014706860995556L;
|
||||
private static final long serialVersionUID = -760014706860995557L;
|
||||
|
||||
private final String cloudName;
|
||||
|
||||
private final String adminUserName;
|
||||
private final String vmCredentialsId;
|
||||
|
||||
private final String azureCredentialsId;
|
||||
|
||||
private transient final AzureCredentials.ServicePrincipal credentials;
|
||||
|
||||
private final String sshPrivateKey;
|
||||
|
||||
private final String sshPassPhrase;
|
||||
|
||||
private final String adminPassword;
|
||||
|
||||
private final String jvmOptions;
|
||||
|
||||
private boolean shutdownOnIdle;
|
||||
|
@ -77,16 +80,6 @@ public class AzureVMAgent extends AbstractCloudSlave {
|
|||
|
||||
private final Mode mode;
|
||||
|
||||
private final String subscriptionId;
|
||||
|
||||
private final String clientId;
|
||||
|
||||
private final String clientSecret;
|
||||
|
||||
private final String oauth2TokenEndpoint;
|
||||
|
||||
private final String managementURL;
|
||||
|
||||
private String templateName;
|
||||
|
||||
private CleanUpAction cleanUpAction;
|
||||
|
@ -117,21 +110,17 @@ public class AzureVMAgent extends AbstractCloudSlave {
|
|||
final RetentionStrategy<AzureVMComputer> retentionStrategy,
|
||||
final List<? extends NodeProperty<?>> nodeProperties,
|
||||
final String cloudName,
|
||||
final String adminUserName,
|
||||
final String vmCredentialsId,
|
||||
final String sshPrivateKey,
|
||||
final String sshPassPhrase,
|
||||
final String adminPassword,
|
||||
final String jvmOptions,
|
||||
final boolean shutdownOnIdle,
|
||||
final boolean eligibleForReuse,
|
||||
final String deploymentName,
|
||||
final int retentionTimeInMin,
|
||||
final String initScript,
|
||||
final String subscriptionId,
|
||||
final String clientId,
|
||||
final String clientSecret,
|
||||
final String oauth2TokenEndpoint,
|
||||
final String managementURL,
|
||||
final String azureCredentialsId,
|
||||
final AzureCredentials.ServicePrincipal servicePrincipal,
|
||||
final String agentLaunchMethod,
|
||||
final CleanUpAction cleanUpAction,
|
||||
final Localizable cleanUpReason,
|
||||
|
@ -143,10 +132,11 @@ public class AzureVMAgent extends AbstractCloudSlave {
|
|||
|
||||
this.cloudName = cloudName;
|
||||
this.templateName = templateName;
|
||||
this.adminUserName = adminUserName;
|
||||
this.vmCredentialsId = vmCredentialsId;
|
||||
this.azureCredentialsId = azureCredentialsId;
|
||||
this.credentials = servicePrincipal;
|
||||
this.sshPrivateKey = sshPrivateKey;
|
||||
this.sshPassPhrase = sshPassPhrase;
|
||||
this.adminPassword = adminPassword;
|
||||
this.jvmOptions = jvmOptions;
|
||||
this.shutdownOnIdle = shutdownOnIdle;
|
||||
this.eligibleForReuse = eligibleForReuse;
|
||||
|
@ -155,11 +145,6 @@ public class AzureVMAgent extends AbstractCloudSlave {
|
|||
this.initScript = initScript;
|
||||
this.osType = osType;
|
||||
this.mode = mode;
|
||||
this.subscriptionId = subscriptionId;
|
||||
this.clientId = clientId;
|
||||
this.clientSecret = clientSecret;
|
||||
this.oauth2TokenEndpoint = oauth2TokenEndpoint;
|
||||
this.managementURL = managementURL;
|
||||
this.agentLaunchMethod = agentLaunchMethod;
|
||||
this.setCleanUpAction(cleanUpAction);
|
||||
this.setCleanupReason(cleanUpReason);
|
||||
|
@ -178,21 +163,17 @@ public class AzureVMAgent extends AbstractCloudSlave {
|
|||
final Mode mode,
|
||||
final String label,
|
||||
final String cloudName,
|
||||
final String adminUserName,
|
||||
final String vmCredentialsId,
|
||||
final String sshPrivateKey,
|
||||
final String sshPassPhrase,
|
||||
final String adminPassword,
|
||||
final String jvmOptions,
|
||||
final boolean shutdownOnIdle,
|
||||
final boolean eligibleForReuse,
|
||||
final String deploymentName,
|
||||
final int retentionTimeInMin,
|
||||
final String initScript,
|
||||
final String subscriptionId,
|
||||
final String clientId,
|
||||
final String clientSecret,
|
||||
final String oauth2TokenEndpoint,
|
||||
final String managementURL,
|
||||
final String azureCredentialsId,
|
||||
final AzureCredentials.ServicePrincipal servicePrincipal,
|
||||
final String agentLaunchMethod,
|
||||
final CleanUpAction cleanUpAction,
|
||||
final Localizable cleanUpReason,
|
||||
|
@ -213,21 +194,17 @@ public class AzureVMAgent extends AbstractCloudSlave {
|
|||
new AzureVMCloudRetensionStrategy(retentionTimeInMin),
|
||||
Collections.<NodeProperty<?>>emptyList(),
|
||||
cloudName,
|
||||
adminUserName,
|
||||
vmCredentialsId,
|
||||
sshPrivateKey,
|
||||
sshPassPhrase,
|
||||
adminPassword,
|
||||
jvmOptions,
|
||||
shutdownOnIdle,
|
||||
eligibleForReuse,
|
||||
deploymentName,
|
||||
retentionTimeInMin,
|
||||
initScript,
|
||||
subscriptionId,
|
||||
clientId,
|
||||
clientSecret,
|
||||
oauth2TokenEndpoint,
|
||||
managementURL,
|
||||
azureCredentialsId,
|
||||
servicePrincipal,
|
||||
agentLaunchMethod,
|
||||
cleanUpAction,
|
||||
cleanUpReason,
|
||||
|
@ -245,28 +222,15 @@ public class AzureVMAgent extends AbstractCloudSlave {
|
|||
return mode;
|
||||
}
|
||||
|
||||
public String getAdminUserName() {
|
||||
return adminUserName;
|
||||
public String getVMCredentialsId() {
|
||||
return vmCredentialsId;
|
||||
}
|
||||
|
||||
public String getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public String getClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
|
||||
public String getOauth2TokenEndpoint() {
|
||||
return oauth2TokenEndpoint;
|
||||
}
|
||||
|
||||
public String getManagementURL() {
|
||||
return managementURL;
|
||||
public AzureCredentials.ServicePrincipal getServicePrincipal()
|
||||
{
|
||||
if(credentials == null && azureCredentialsId != null)
|
||||
return AzureCredentials.getServicePrincipal(azureCredentialsId);
|
||||
return credentials;
|
||||
}
|
||||
|
||||
public String getSshPrivateKey() {
|
||||
|
@ -285,10 +249,6 @@ public class AzureVMAgent extends AbstractCloudSlave {
|
|||
return deploymentName;
|
||||
}
|
||||
|
||||
public String getAdminPassword() {
|
||||
return adminPassword;
|
||||
}
|
||||
|
||||
public CleanUpAction getCleanUpAction() {
|
||||
return cleanUpAction;
|
||||
}
|
||||
|
@ -478,7 +438,7 @@ public class AzureVMAgent extends AbstractCloudSlave {
|
|||
public String toString() {
|
||||
return "AzureVMAgent ["
|
||||
+ "\n\tcloudName=" + cloudName
|
||||
+ "\n\tadminUserName=" + adminUserName
|
||||
+ "\n\tVMCredentialsId=" + vmCredentialsId
|
||||
+ "\n\tjvmOptions=" + jvmOptions
|
||||
+ "\n\tshutdownOnIdle=" + shutdownOnIdle
|
||||
+ "\n\tretentionTimeInMin=" + retentionTimeInMin
|
||||
|
@ -489,7 +449,7 @@ public class AzureVMAgent extends AbstractCloudSlave {
|
|||
+ "\n\tpublicDNSName=" + publicDNSName
|
||||
+ "\n\tsshPort=" + sshPort
|
||||
+ "\n\tmode=" + mode
|
||||
+ "\n\tmanagementURL=" + managementURL
|
||||
+ "\n\tmanagementURL=" + credentials.serviceManagementURL == null ? "<none>" : credentials.serviceManagementURL
|
||||
+ "\n\ttemplateName=" + templateName
|
||||
+ "\n\tcleanUpAction=" + cleanUpAction
|
||||
+ "\n]";
|
||||
|
|
|
@ -15,7 +15,16 @@
|
|||
*/
|
||||
package com.microsoft.azure;
|
||||
|
||||
import com.cloudbees.plugins.credentials.CredentialsMatcher;
|
||||
import com.cloudbees.plugins.credentials.CredentialsMatchers;
|
||||
import com.cloudbees.plugins.credentials.CredentialsProvider;
|
||||
import com.cloudbees.plugins.credentials.common.StandardCredentials;
|
||||
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
|
||||
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
|
||||
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
|
||||
import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder;
|
||||
import com.microsoft.azure.Messages;
|
||||
import com.microsoft.azure.util.AzureCredentials;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -38,15 +47,21 @@ import hudson.RelativePath;
|
|||
import hudson.model.Describable;
|
||||
import hudson.model.TaskListener;
|
||||
import hudson.model.Descriptor;
|
||||
import hudson.model.Item;
|
||||
import hudson.model.Label;
|
||||
import hudson.model.Node;
|
||||
import hudson.model.labels.LabelAtom;
|
||||
import hudson.security.ACL;
|
||||
import hudson.util.FormValidation;
|
||||
import hudson.util.ListBoxModel;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jenkinsci.plugins.plaincredentials.StringCredentials;
|
||||
import org.kohsuke.stapler.AncestorInPath;
|
||||
|
||||
/**
|
||||
* This class defines the configuration of Azure instance templates
|
||||
|
@ -96,9 +111,7 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
|
|||
|
||||
private final String initScript;
|
||||
|
||||
private final String adminUserName;
|
||||
|
||||
private final String adminPassword;
|
||||
private final String credentialsId;
|
||||
|
||||
private final String agentWorkspace;
|
||||
|
||||
|
@ -146,8 +159,7 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
|
|||
final String imageVersion,
|
||||
final String agentLaunchMethod,
|
||||
final String initScript,
|
||||
final String adminUserName,
|
||||
final String adminPassword,
|
||||
final String credentialsId,
|
||||
final String virtualNetworkName,
|
||||
final String subnetName,
|
||||
final String agentWorkspace,
|
||||
|
@ -182,8 +194,7 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
|
|||
this.shutdownOnIdle = shutdownOnIdle;
|
||||
this.initScript = initScript;
|
||||
this.agentLaunchMethod = agentLaunchMethod;
|
||||
this.adminUserName = adminUserName;
|
||||
this.adminPassword = adminPassword;
|
||||
this.credentialsId = credentialsId;
|
||||
this.virtualNetworkName = virtualNetworkName;
|
||||
this.subnetName = subnetName;
|
||||
this.agentWorkspace = agentWorkspace;
|
||||
|
@ -274,12 +285,8 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
|
|||
return initScript;
|
||||
}
|
||||
|
||||
public String getAdminUserName() {
|
||||
return adminUserName;
|
||||
}
|
||||
|
||||
public String getAdminPassword() {
|
||||
return adminPassword;
|
||||
public String getCredentialsId() {
|
||||
return credentialsId;
|
||||
}
|
||||
|
||||
public String getVirtualNetworkName() {
|
||||
|
@ -425,11 +432,8 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
|
|||
* @throws Exception
|
||||
*/
|
||||
public List<String> verifyTemplate() throws Exception {
|
||||
return AzureVMManagementServiceDelegate.verifyTemplate(azureCloud.getSubscriptionId(),
|
||||
azureCloud.getClientId(),
|
||||
azureCloud.getClientSecret(),
|
||||
azureCloud.getOauth2TokenEndpoint(),
|
||||
azureCloud.getServiceManagementURL(),
|
||||
return AzureVMManagementServiceDelegate.verifyTemplate(
|
||||
azureCloud.getServicePrincipal(),
|
||||
templateName,
|
||||
labels,
|
||||
location,
|
||||
|
@ -444,8 +448,7 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
|
|||
imageVersion,
|
||||
agentLaunchMethod,
|
||||
initScript,
|
||||
adminUserName,
|
||||
adminPassword,
|
||||
credentialsId,
|
||||
virtualNetworkName,
|
||||
subnetName,
|
||||
retentionTimeInMin + "",
|
||||
|
@ -478,6 +481,13 @@ 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
|
||||
// (which we cannot assume) thus ACL.SYSTEM is correct here.
|
||||
return new StandardListBoxModel().withAll(CredentialsProvider.lookupCredentials(StandardUsernamePasswordCredentials.class, owner, ACL.SYSTEM, Collections.<DomainRequirement>emptyList()));
|
||||
}
|
||||
|
||||
public ListBoxModel doFillOsTypeItems() throws IOException, ServletException {
|
||||
ListBoxModel model = new ListBoxModel();
|
||||
|
@ -564,17 +574,6 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
|
|||
return FormValidation.ok();
|
||||
}
|
||||
|
||||
public FormValidation doCheckAdminUserName(@QueryParameter final String value) {
|
||||
if (StringUtils.isNotBlank(value)) {
|
||||
if (AzureUtil.isValidUserName(value)) {
|
||||
return FormValidation.ok();
|
||||
} else {
|
||||
return FormValidation.error(Messages.Azure_GC_UserName_Err());
|
||||
}
|
||||
}
|
||||
return FormValidation.ok();
|
||||
}
|
||||
|
||||
public FormValidation doCheckNoOfParallelJobs(@QueryParameter final String value) {
|
||||
if (StringUtils.isNotBlank(value)) {
|
||||
String result = AzureVMManagementServiceDelegate.verifyNoOfExecutors(value);
|
||||
|
@ -624,11 +623,7 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
|
|||
}
|
||||
|
||||
public FormValidation doVerifyConfiguration(
|
||||
@RelativePath("..") @QueryParameter String subscriptionId,
|
||||
@RelativePath("..") @QueryParameter String clientId,
|
||||
@RelativePath("..") @QueryParameter String clientSecret,
|
||||
@RelativePath("..") @QueryParameter String oauth2TokenEndpoint,
|
||||
@RelativePath("..") @QueryParameter String serviceManagementURL,
|
||||
@RelativePath("..") @QueryParameter String azureCredentialsId,
|
||||
@RelativePath("..") @QueryParameter String resourceGroupName,
|
||||
@QueryParameter String templateName,
|
||||
@QueryParameter String labels,
|
||||
|
@ -644,19 +639,18 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
|
|||
@QueryParameter String imageVersion,
|
||||
@QueryParameter String agentLaunchMethod,
|
||||
@QueryParameter String initScript,
|
||||
@QueryParameter String adminUserName,
|
||||
@QueryParameter String adminPassword,
|
||||
@QueryParameter String credentialsId,
|
||||
@QueryParameter String virtualNetworkName,
|
||||
@QueryParameter String subnetName,
|
||||
@QueryParameter String retentionTimeInMin,
|
||||
@QueryParameter String jvmOptions) {
|
||||
|
||||
AzureCredentials.ServicePrincipal servicePrincipal = AzureCredentials.getServicePrincipal(azureCredentialsId);
|
||||
LOGGER.log(Level.INFO,
|
||||
"Verify configuration:\n\t"
|
||||
+ "subscriptionId: {0};\n\t"
|
||||
+ "clientId: {1};\n\t"
|
||||
+ "clientSecret: {2};\n\t"
|
||||
+ "oauth2TokenEndpoint: {3};\n\t"
|
||||
+ "serviceManagementURL: {4};\n\t"
|
||||
+ "resourceGroupName: {5};\n\t."
|
||||
+ "templateName: {6};\n\t"
|
||||
|
@ -673,18 +667,16 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
|
|||
+ "imageVersion: {17};\n\t"
|
||||
+ "agentLaunchMethod: {18};\n\t"
|
||||
+ "initScript: {19};\n\t"
|
||||
+ "adminUserName: {20};\n\t"
|
||||
+ "adminPassword: {21};\n\t"
|
||||
+ "virtualNetworkName: {22};\n\t"
|
||||
+ "subnetName: {23};\n\t"
|
||||
+ "retentionTimeInMin: {24};\n\t"
|
||||
+ "jvmOptions: {25};",
|
||||
+ "credentialsId: {20};\n\t"
|
||||
+ "virtualNetworkName: {21};\n\t"
|
||||
+ "subnetName: {22};\n\t"
|
||||
+ "retentionTimeInMin: {23};\n\t"
|
||||
+ "jvmOptions: {24};",
|
||||
new Object[] {
|
||||
subscriptionId,
|
||||
clientId,
|
||||
(StringUtils.isNotBlank(clientSecret) ? "********" : null),
|
||||
oauth2TokenEndpoint,
|
||||
serviceManagementURL,
|
||||
servicePrincipal.subscriptionId.getPlainText(),
|
||||
(StringUtils.isNotBlank(servicePrincipal.clientId.getPlainText()) ? "********" : null),
|
||||
(StringUtils.isNotBlank(servicePrincipal.clientSecret.getPlainText()) ? "********" : null),
|
||||
servicePrincipal.serviceManagementURL,
|
||||
resourceGroupName,
|
||||
templateName,
|
||||
labels,
|
||||
|
@ -700,8 +692,7 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
|
|||
imageVersion,
|
||||
agentLaunchMethod,
|
||||
initScript,
|
||||
adminUserName,
|
||||
(StringUtils.isNotBlank(adminPassword) ? "********" : null),
|
||||
credentialsId,
|
||||
virtualNetworkName,
|
||||
subnetName,
|
||||
retentionTimeInMin,
|
||||
|
@ -710,18 +701,13 @@ 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(
|
||||
subscriptionId, clientId, clientSecret, oauth2TokenEndpoint, serviceManagementURL, resourceGroupName);
|
||||
String result = AzureVMManagementServiceDelegate.verifyConfiguration(servicePrincipal, resourceGroupName);
|
||||
if (!result.equals(Constants.OP_SUCCESS)) {
|
||||
return FormValidation.error(result);
|
||||
}
|
||||
|
||||
final List<String> errors = AzureVMManagementServiceDelegate.verifyTemplate(
|
||||
subscriptionId,
|
||||
clientId,
|
||||
clientSecret,
|
||||
oauth2TokenEndpoint,
|
||||
serviceManagementURL,
|
||||
servicePrincipal,
|
||||
templateName,
|
||||
labels,
|
||||
location,
|
||||
|
@ -736,8 +722,7 @@ public class AzureVMAgentTemplate implements Describable<AzureVMAgentTemplate> {
|
|||
imageVersion,
|
||||
agentLaunchMethod,
|
||||
initScript,
|
||||
adminUserName,
|
||||
adminPassword,
|
||||
credentialsId,
|
||||
virtualNetworkName,
|
||||
subnetName,
|
||||
retentionTimeInMin,
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
*/
|
||||
package com.microsoft.azure;
|
||||
|
||||
import com.cloudbees.plugins.credentials.CredentialsProvider;
|
||||
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
|
||||
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
|
||||
import com.microsoft.azure.management.compute.models.VirtualMachineGetResponse;
|
||||
import com.microsoft.azure.management.resources.ResourceManagementClient;
|
||||
import com.microsoft.azure.management.resources.ResourceManagementService;
|
||||
|
@ -22,6 +25,8 @@ import com.microsoft.azure.management.resources.models.DeploymentOperation;
|
|||
import com.microsoft.azure.management.resources.models.ProvisioningState;
|
||||
import com.microsoft.windowsazure.Configuration;
|
||||
import com.microsoft.azure.exceptions.AzureCloudException;
|
||||
import com.microsoft.azure.exceptions.AzureCredentialsValidationException;
|
||||
import com.microsoft.azure.util.AzureCredentials;
|
||||
import com.microsoft.azure.util.AzureUtil;
|
||||
import com.microsoft.azure.util.CleanUpAction;
|
||||
import com.microsoft.azure.util.AzureUserAgentFilter;
|
||||
|
@ -53,87 +58,83 @@ import hudson.util.StreamTaskListener;
|
|||
|
||||
import com.microsoft.azure.util.Constants;
|
||||
import com.microsoft.azure.util.FailureStage;
|
||||
import hudson.model.Item;
|
||||
import hudson.security.ACL;
|
||||
import hudson.util.ListBoxModel;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.logging.Level;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.kohsuke.stapler.AncestorInPath;
|
||||
|
||||
public class AzureVMCloud extends Cloud {
|
||||
|
||||
public static final Logger LOGGER = Logger.getLogger(AzureVMCloud.class.getName());
|
||||
|
||||
private final String subscriptionId;
|
||||
private transient final AzureCredentials.ServicePrincipal credentials;
|
||||
|
||||
private final String clientId;
|
||||
|
||||
private final String clientSecret;
|
||||
|
||||
private final String oauth2TokenEndpoint;
|
||||
|
||||
private final String serviceManagementURL;
|
||||
private final String credentialsId;
|
||||
|
||||
private final int maxVirtualMachinesLimit;
|
||||
|
||||
|
||||
private final String resourceGroupName;
|
||||
|
||||
private final List<AzureVMAgentTemplate> instTemplates;
|
||||
|
||||
|
||||
private final int deploymentTimeout;
|
||||
|
||||
|
||||
// True if the subscription has been verified.
|
||||
// False otherwise.
|
||||
private transient boolean configurationValid;
|
||||
|
||||
|
||||
// Approximate virtual machine count. Updated periodically.
|
||||
private int approximateVirtualMachineCount;
|
||||
|
||||
@DataBoundConstructor
|
||||
public AzureVMCloud(
|
||||
final String id,
|
||||
final String subscriptionId,
|
||||
final String clientId,
|
||||
final String clientSecret,
|
||||
final String oauth2TokenEndpoint,
|
||||
final String serviceManagementURL,
|
||||
final String azureCredentialsId,
|
||||
final String maxVirtualMachinesLimit,
|
||||
final String deploymentTimeout,
|
||||
final String resourceGroupName,
|
||||
final List<AzureVMAgentTemplate> instTemplates) {
|
||||
this(AzureCredentials.getServicePrincipal(azureCredentialsId), azureCredentialsId, maxVirtualMachinesLimit, deploymentTimeout, resourceGroupName, instTemplates);
|
||||
}
|
||||
|
||||
super(AzureUtil.getCloudName(subscriptionId));
|
||||
|
||||
this.subscriptionId = subscriptionId;
|
||||
this.clientId = clientId;
|
||||
this.clientSecret = clientSecret;
|
||||
this.oauth2TokenEndpoint = oauth2TokenEndpoint;
|
||||
private AzureVMCloud(
|
||||
AzureCredentials.ServicePrincipal credentials,
|
||||
final String azureCredentialsId,
|
||||
final String maxVirtualMachinesLimit,
|
||||
final String deploymentTimeout,
|
||||
final String resourceGroupName,
|
||||
final List<AzureVMAgentTemplate> instTemplates) {
|
||||
super(AzureUtil.getCloudName(credentials.subscriptionId.getPlainText()));
|
||||
this.credentials = credentials;
|
||||
this.credentialsId = azureCredentialsId;
|
||||
this.resourceGroupName = resourceGroupName;
|
||||
|
||||
this.serviceManagementURL = StringUtils.isBlank(serviceManagementURL)
|
||||
? Constants.DEFAULT_MANAGEMENT_URL
|
||||
: serviceManagementURL;
|
||||
|
||||
if (StringUtils.isBlank(maxVirtualMachinesLimit) || !maxVirtualMachinesLimit.matches(Constants.REG_EX_DIGIT)) {
|
||||
this.maxVirtualMachinesLimit = Constants.DEFAULT_MAX_VM_LIMIT;
|
||||
} else {
|
||||
this.maxVirtualMachinesLimit = Integer.parseInt(maxVirtualMachinesLimit);
|
||||
}
|
||||
|
||||
|
||||
if (StringUtils.isBlank(deploymentTimeout) || !deploymentTimeout.matches(Constants.REG_EX_DIGIT)) {
|
||||
this.deploymentTimeout = Constants.DEFAULT_DEPLOYMENT_TIMEOUT_SEC;
|
||||
} else {
|
||||
this.deploymentTimeout = Integer.parseInt(deploymentTimeout);
|
||||
}
|
||||
|
||||
|
||||
this.configurationValid = false;
|
||||
|
||||
|
||||
this.instTemplates = instTemplates == null
|
||||
? Collections.<AzureVMAgentTemplate>emptyList()
|
||||
: instTemplates;
|
||||
|
||||
|
||||
readResolve();
|
||||
|
||||
|
||||
registerVerificationIfNeeded();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register the initial verification if required
|
||||
*/
|
||||
|
@ -167,7 +168,7 @@ public class AzureVMCloud extends Cloud {
|
|||
if (!this.isConfigurationValid()) {
|
||||
LOGGER.log(Level.INFO, "AzureVMCloud: canProvision: Subscription not verified, or is invalid, cannot provision");
|
||||
}
|
||||
|
||||
|
||||
final AzureVMAgentTemplate template = AzureVMCloud.this.getAzureAgentTemplate(label);
|
||||
// return false if there is no template for this label.
|
||||
if (template == null) {
|
||||
|
@ -183,8 +184,8 @@ public class AzureVMCloud extends Cloud {
|
|||
// The template is available, but not verified. It may be queued for
|
||||
// verification, but ensure that it's added.
|
||||
LOGGER.log(Level.INFO,
|
||||
"AzureVMCloud: canProvision: template {0} is awaiting verification or has failed verification",
|
||||
template.getTemplateName());
|
||||
"AzureVMCloud: canProvision: template {0} is awaiting verification or has failed verification",
|
||||
template.getTemplateName());
|
||||
AzureVMCloudVerificationTask.registerTemplate(template);
|
||||
return false;
|
||||
} else {
|
||||
|
@ -192,30 +193,10 @@ public class AzureVMCloud extends Cloud {
|
|||
}
|
||||
}
|
||||
|
||||
public String getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public String getOauth2TokenEndpoint() {
|
||||
return oauth2TokenEndpoint;
|
||||
}
|
||||
|
||||
public String getClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
|
||||
public String getServiceManagementURL() {
|
||||
return serviceManagementURL;
|
||||
}
|
||||
|
||||
public int getMaxVirtualMachinesLimit() {
|
||||
return maxVirtualMachinesLimit;
|
||||
}
|
||||
|
||||
|
||||
public String getResourceGroupName() {
|
||||
return resourceGroupName;
|
||||
}
|
||||
|
@ -223,45 +204,60 @@ public class AzureVMCloud extends Cloud {
|
|||
public int getDeploymentTimeout() {
|
||||
return deploymentTimeout;
|
||||
}
|
||||
|
||||
|
||||
public String getAzureCredentialsId() {
|
||||
return credentialsId;
|
||||
}
|
||||
|
||||
public AzureCredentials.ServicePrincipal getServicePrincipal()
|
||||
{
|
||||
if(credentials == null && credentialsId != null)
|
||||
return AzureCredentials.getServicePrincipal(credentialsId);
|
||||
return credentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current set of templates.
|
||||
* Required for config.jelly
|
||||
* @return
|
||||
* Returns the current set of templates. Required for config.jelly
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<AzureVMAgentTemplate> getInstTemplates() {
|
||||
return Collections.unmodifiableList(instTemplates);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is the configuration set up and verified?
|
||||
*
|
||||
* @return True if the configuration set up and verified, false otherwise.
|
||||
*/
|
||||
public boolean isConfigurationValid() {
|
||||
return configurationValid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the configuration verification status
|
||||
*
|
||||
* @param isValid True for verified + valid, false otherwise.
|
||||
*/
|
||||
public void setConfigurationValid(boolean isValid) {
|
||||
configurationValid = isValid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the current approximate virtual machine count
|
||||
* @return
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getApproximateVirtualMachineCount() {
|
||||
synchronized (this) {
|
||||
return approximateVirtualMachineCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given the number of VMs that are desired, returns the number
|
||||
* of VMs that can be allocated.
|
||||
* Given the number of VMs that are desired, returns the number of VMs that
|
||||
* can be allocated.
|
||||
*
|
||||
* @param quantityDesired Number that are desired
|
||||
* @return Number that can be allocated
|
||||
*/
|
||||
|
@ -270,8 +266,7 @@ public class AzureVMCloud extends Cloud {
|
|||
if (approximateVirtualMachineCount + quantityDesired <= getMaxVirtualMachinesLimit()) {
|
||||
// Enough available, return the desired quantity
|
||||
return quantityDesired;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Not enough available, return what we have. Remember we could
|
||||
// go negative (if for instance another Jenkins instance had
|
||||
// a higher limit.
|
||||
|
@ -279,9 +274,10 @@ public class AzureVMCloud extends Cloud {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adjust the number of currently allocated VMs
|
||||
*
|
||||
* @param delta Number to adjust by.
|
||||
*/
|
||||
public void adjustVirtualMachineCount(int delta) {
|
||||
|
@ -289,18 +285,19 @@ public class AzureVMCloud extends Cloud {
|
|||
approximateVirtualMachineCount = Math.max(0, approximateVirtualMachineCount + delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the new approximate virtual machine count. This is run by
|
||||
* the verification task to update the VM count periodically.
|
||||
* @param newCount
|
||||
* Sets the new approximate virtual machine count. This is run by the
|
||||
* verification task to update the VM count periodically.
|
||||
*
|
||||
* @param newCount
|
||||
*/
|
||||
public void setVirtualMachineCount(int newCount) {
|
||||
synchronized (this) {
|
||||
approximateVirtualMachineCount = newCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns agent template associated with the label.
|
||||
*
|
||||
|
@ -348,12 +345,13 @@ public class AzureVMCloud extends Cloud {
|
|||
/**
|
||||
* Once a new deployment is created, construct a new AzureVMAgent object
|
||||
* given information about the template
|
||||
*
|
||||
* @param template Template used to create the new agent
|
||||
* @param vmName Name of the created VM
|
||||
* @param deploymentName Name of the deployment containing the VM
|
||||
* @param config Azure configuration.
|
||||
* @return New agent. Throws otherwise.
|
||||
* @throws Exception
|
||||
* @return New agent. Throws otherwise.
|
||||
* @throws Exception
|
||||
*/
|
||||
private AzureVMAgent createProvisionedAgent(
|
||||
final AzureVMAgentTemplate template,
|
||||
|
@ -361,7 +359,7 @@ public class AzureVMCloud extends Cloud {
|
|||
final String deploymentName) throws Exception {
|
||||
|
||||
LOGGER.log(Level.INFO, "AzureVMCloud: createProvisionedAgent: Waiting for deployment {0} to be completed", deploymentName);
|
||||
|
||||
|
||||
final int sleepTimeInSeconds = 30;
|
||||
final int timeoutInSeconds = getDeploymentTimeout();
|
||||
final int maxTries = timeoutInSeconds / sleepTimeInSeconds;
|
||||
|
@ -373,16 +371,16 @@ public class AzureVMCloud extends Cloud {
|
|||
} catch (InterruptedException ex) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
|
||||
// Create a new RM client each time because the config may expire while
|
||||
// in this long running operation
|
||||
Configuration config = ServiceDelegateHelper.getConfiguration(template);
|
||||
final ResourceManagementClient rmc = ResourceManagementService.create(config)
|
||||
.withRequestFilterFirst(new AzureUserAgentFilter());
|
||||
|
||||
.withRequestFilterFirst(new AzureUserAgentFilter());
|
||||
|
||||
final List<DeploymentOperation> ops = rmc.getDeploymentOperationsOperations().
|
||||
list(resourceGroupName, deploymentName, null).getOperations();
|
||||
|
||||
|
||||
for (DeploymentOperation op : ops) {
|
||||
final String resource = op.getProperties().getTargetResource().getResourceName();
|
||||
final String type = op.getProperties().getTargetResource().getResourceType();
|
||||
|
@ -400,14 +398,14 @@ public class AzureVMCloud extends Cloud {
|
|||
finalStatusMessage += " - " + statusMessage;
|
||||
}
|
||||
|
||||
throw new AzureCloudException(String.format("AzureVMCloud: createProvisionedAgent: Deployment %s: %s:%s - %s", new Object[] { state, type, resource, finalStatusMessage }));
|
||||
throw new AzureCloudException(String.format("AzureVMCloud: createProvisionedAgent: Deployment %s: %s:%s - %s", new Object[]{state, type, resource, finalStatusMessage}));
|
||||
} else if (ProvisioningState.SUCCEEDED.equals(state)) {
|
||||
LOGGER.log(Level.INFO, "AzureVMCloud: createProvisionedAgent: VM available: {0}", resource);
|
||||
|
||||
final VirtualMachineGetResponse vm
|
||||
= ServiceDelegateHelper.getComputeManagementClient(config).
|
||||
getVirtualMachinesOperations().
|
||||
getWithInstanceView(resourceGroupName, resource);
|
||||
getVirtualMachinesOperations().
|
||||
getWithInstanceView(resourceGroupName, resource);
|
||||
|
||||
final String osType = vm.getVirtualMachine().getStorageProfile().getOSDisk().
|
||||
getOperatingSystemType();
|
||||
|
@ -416,11 +414,10 @@ public class AzureVMCloud extends Cloud {
|
|||
// Set the virtual machine details
|
||||
AzureVMManagementServiceDelegate.setVirtualMachineDetails(newAgent, template);
|
||||
return newAgent;
|
||||
}
|
||||
else {
|
||||
LOGGER.log(Level.INFO, "AzureVMCloud: createProvisionedAgent: Deployment {0} not yet finished ({1}): {2}:{3} - waited {4} seconds",
|
||||
new Object[] { deploymentName, state, type, resource,
|
||||
(maxTries - triesLeft) * sleepTimeInSeconds });
|
||||
} else {
|
||||
LOGGER.log(Level.INFO, "AzureVMCloud: createProvisionedAgent: Deployment {0} not yet finished ({1}): {2}:{3} - waited {4} seconds",
|
||||
new Object[]{deploymentName, state, type, resource,
|
||||
(maxTries - triesLeft) * sleepTimeInSeconds});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -433,7 +430,7 @@ public class AzureVMCloud extends Cloud {
|
|||
@Override
|
||||
public Collection<PlannedNode> provision(final Label label, int workLoad) {
|
||||
LOGGER.log(Level.INFO,
|
||||
"AzureVMCloud: provision: start for label {0} workLoad {1}", new Object[] { label, workLoad });
|
||||
"AzureVMCloud: provision: start for label {0} workLoad {1}", new Object[]{label, workLoad});
|
||||
|
||||
final AzureVMAgentTemplate template = AzureVMCloud.this.getAzureAgentTemplate(label);
|
||||
|
||||
|
@ -444,7 +441,7 @@ public class AzureVMCloud extends Cloud {
|
|||
// reuse existing nodes if available
|
||||
LOGGER.log(Level.INFO, "AzureVMCloud: provision: checking for node reuse options");
|
||||
for (Computer agentComputer : Jenkins.getInstance().getComputers()) {
|
||||
if (numberOfAgents == 0) {
|
||||
if (numberOfAgents == 0) {
|
||||
break;
|
||||
}
|
||||
if (agentComputer instanceof AzureVMComputer && agentComputer.isOffline()) {
|
||||
|
@ -500,19 +497,18 @@ public class AzureVMCloud extends Cloud {
|
|||
int adjustedNumberOfAgents = getAvailableVirtualMachineCount(numberOfAgents);
|
||||
if (adjustedNumberOfAgents == 0) {
|
||||
LOGGER.log(Level.INFO, "Not able to create any new nodes, at or above maximum VM count of {0}",
|
||||
getMaxVirtualMachinesLimit());
|
||||
getMaxVirtualMachinesLimit());
|
||||
return plannedNodes;
|
||||
}
|
||||
else if (adjustedNumberOfAgents < numberOfAgents) {
|
||||
} else if (adjustedNumberOfAgents < numberOfAgents) {
|
||||
LOGGER.log(Level.INFO, "Able to create new nodes, but can only create {0} (desired {1})",
|
||||
new Object[] { adjustedNumberOfAgents, numberOfAgents } );
|
||||
new Object[]{adjustedNumberOfAgents, numberOfAgents});
|
||||
}
|
||||
final int numberOfNewAgents = adjustedNumberOfAgents;
|
||||
|
||||
// Adjust number of nodes available by the number of created nodes.
|
||||
// Negative to reduce number available.
|
||||
this.adjustVirtualMachineCount(-adjustedNumberOfAgents);
|
||||
|
||||
|
||||
ExecutorService executorService = Executors.newCachedThreadPool();
|
||||
Callable<AzureVMDeploymentInfo> callableTask = new Callable<AzureVMDeploymentInfo>() {
|
||||
@Override
|
||||
|
@ -530,31 +526,30 @@ public class AzureVMCloud extends Cloud {
|
|||
|
||||
@Override
|
||||
public Node call() throws Exception {
|
||||
|
||||
|
||||
// Wait for the future to complete
|
||||
AzureVMDeploymentInfo info = deploymentFuture.get();
|
||||
|
||||
|
||||
final String deploymentName = info.getDeploymentName();
|
||||
final String vmBaseName = info.getVmBaseName();
|
||||
final String vmName = String.format("%s%d", vmBaseName, index);
|
||||
|
||||
|
||||
AzureVMAgent agent = null;
|
||||
try {
|
||||
agent = createProvisionedAgent(
|
||||
template,
|
||||
vmName,
|
||||
deploymentName);
|
||||
}
|
||||
catch (Exception e) {
|
||||
template,
|
||||
vmName,
|
||||
deploymentName);
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(
|
||||
Level.SEVERE,
|
||||
String.format("Failure creating provisioned agent '%s'", vmName),
|
||||
e);
|
||||
|
||||
Level.SEVERE,
|
||||
String.format("Failure creating provisioned agent '%s'", vmName),
|
||||
e);
|
||||
|
||||
// Attempt to terminate whatever was created
|
||||
AzureVMManagementServiceDelegate.terminateVirtualMachine(
|
||||
ServiceDelegateHelper.getConfiguration(template), vmName,
|
||||
template.getResourceGroupName());
|
||||
ServiceDelegateHelper.getConfiguration(template), vmName,
|
||||
template.getResourceGroupName());
|
||||
template.getAzureCloud().adjustVirtualMachineCount(1);
|
||||
// Update the template status given this new issue.
|
||||
template.handleTemplateProvisioningFailure(e.getMessage(), FailureStage.PROVISIONING);
|
||||
|
@ -577,19 +572,19 @@ public class AzureVMCloud extends Cloud {
|
|||
agent.clearCleanUpAction();
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(
|
||||
Level.SEVERE,
|
||||
String.format("Failure to in post-provisioning for '%s'", vmName),
|
||||
e);
|
||||
|
||||
Level.SEVERE,
|
||||
String.format("Failure to in post-provisioning for '%s'", vmName),
|
||||
e);
|
||||
|
||||
// Attempt to terminate whatever was created
|
||||
AzureVMManagementServiceDelegate.terminateVirtualMachine(
|
||||
ServiceDelegateHelper.getConfiguration(template), vmName,
|
||||
template.getResourceGroupName());
|
||||
ServiceDelegateHelper.getConfiguration(template), vmName,
|
||||
template.getResourceGroupName());
|
||||
template.getAzureCloud().adjustVirtualMachineCount(1);
|
||||
|
||||
|
||||
// Update the template status
|
||||
template.handleTemplateProvisioningFailure(vmName, FailureStage.POSTPROVISIONING);
|
||||
|
||||
|
||||
// Remove the node from jenkins
|
||||
Jenkins.getInstance().removeNode(agent);
|
||||
throw e;
|
||||
|
@ -613,9 +608,12 @@ public class AzureVMCloud extends Cloud {
|
|||
}
|
||||
|
||||
/**
|
||||
* Wait till a node that connects through JNLP comes online and connects to Jenkins.
|
||||
* Wait till a node that connects through JNLP comes online and connects to
|
||||
* Jenkins.
|
||||
*
|
||||
* @param agent Node to wait for
|
||||
* @throws Exception Throws if the wait time expires or other exception happens.
|
||||
* @throws Exception Throws if the wait time expires or other exception
|
||||
* happens.
|
||||
*/
|
||||
private void waitUntilJNLPNodeIsOnline(final AzureVMAgent agent) throws Exception {
|
||||
LOGGER.log(Level.INFO, "Azure Cloud: waitUntilOnline: for agent {0}", agent.getDisplayName());
|
||||
|
@ -682,55 +680,34 @@ public class AzureVMCloud extends Cloud {
|
|||
public int getDefaultMaxVMLimit() {
|
||||
return Constants.DEFAULT_MAX_VM_LIMIT;
|
||||
}
|
||||
|
||||
|
||||
public int getDefaultDeploymentTimeout() {
|
||||
return Constants.DEFAULT_DEPLOYMENT_TIMEOUT_SEC;
|
||||
}
|
||||
|
||||
|
||||
public String getDefaultResourceGroupName() {
|
||||
return Constants.DEFAULT_RESOURCE_GROUP_NAME;
|
||||
}
|
||||
|
||||
public FormValidation doVerifyConfiguration(
|
||||
@QueryParameter String subscriptionId,
|
||||
@QueryParameter String clientId,
|
||||
@QueryParameter String clientSecret,
|
||||
@QueryParameter String oauth2TokenEndpoint,
|
||||
@QueryParameter String serviceManagementURL,
|
||||
@QueryParameter String azureCredentialsId,
|
||||
@QueryParameter String resourceGroupName) {
|
||||
|
||||
if (StringUtils.isBlank(subscriptionId)) {
|
||||
return FormValidation.error("Error: Subscription ID is missing");
|
||||
}
|
||||
if (StringUtils.isBlank(clientId)) {
|
||||
return FormValidation.error("Error: Native Client ID is missing");
|
||||
}
|
||||
if (StringUtils.isBlank(clientSecret)) {
|
||||
return FormValidation.error("Error: Azure Password is missing");
|
||||
}
|
||||
if (StringUtils.isBlank(oauth2TokenEndpoint)) {
|
||||
return FormValidation.error("Error: OAuth 2.0 Token Endpoint is missing");
|
||||
}
|
||||
if (StringUtils.isBlank(serviceManagementURL)) {
|
||||
serviceManagementURL = Constants.DEFAULT_MANAGEMENT_URL;
|
||||
}
|
||||
if (StringUtils.isBlank(resourceGroupName)) {
|
||||
resourceGroupName = Constants.DEFAULT_RESOURCE_GROUP_NAME;
|
||||
}
|
||||
|
||||
String response = AzureVMManagementServiceDelegate.verifyConfiguration(
|
||||
subscriptionId,
|
||||
clientId,
|
||||
clientSecret,
|
||||
oauth2TokenEndpoint,
|
||||
serviceManagementURL,
|
||||
resourceGroupName);
|
||||
|
||||
if (Constants.OP_SUCCESS.equalsIgnoreCase(response)) {
|
||||
return FormValidation.ok(Messages.Azure_Config_Success());
|
||||
} else {
|
||||
return FormValidation.error(response);
|
||||
AzureCredentials.ServicePrincipal credentials = AzureCredentials.getServicePrincipal(azureCredentialsId);
|
||||
try {
|
||||
credentials.Validate(resourceGroupName);
|
||||
} catch (AzureCredentialsValidationException e) {
|
||||
return FormValidation.error(e.getMessage());
|
||||
}
|
||||
return FormValidation.ok(Messages.Azure_Config_Success());
|
||||
}
|
||||
|
||||
public ListBoxModel doFillAzureCredentialsIdItems(@AncestorInPath Item owner) {
|
||||
return new StandardListBoxModel().withAll(CredentialsProvider.lookupCredentials(AzureCredentials.class, owner, ACL.SYSTEM, Collections.<DomainRequirement>emptyList()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package com.microsoft.azure;
|
||||
|
||||
import com.microsoft.azure.util.AzureCredentials;
|
||||
import com.microsoft.windowsazure.Configuration;
|
||||
import com.microsoft.azure.util.AzureUtil;
|
||||
import java.io.IOException;
|
||||
|
@ -203,8 +204,7 @@ public final class AzureVMCloudVerificationTask extends AsyncPeriodicWork {
|
|||
LOGGER.info("AzureVMCloudVerificationTask: verifyConfiguration: start");
|
||||
|
||||
// Check the sub and off we go
|
||||
String result = AzureVMManagementServiceDelegate.verifyConfiguration(cloud.getSubscriptionId(),
|
||||
cloud.getClientId(), cloud.getClientSecret(), cloud.getOauth2TokenEndpoint(), cloud.getServiceManagementURL(), cloud.getResourceGroupName());
|
||||
String result = AzureVMManagementServiceDelegate.verifyConfiguration(cloud.getServicePrincipal(), cloud.getResourceGroupName());
|
||||
if (result != Constants.OP_SUCCESS) {
|
||||
LOGGER.log(Level.INFO, "AzureVMCloudVerificationTask: verifyConfiguration: {0}", result);
|
||||
cloud.setConfigurationValid(false);
|
||||
|
@ -263,7 +263,10 @@ public final class AzureVMCloudVerificationTask extends AsyncPeriodicWork {
|
|||
* @param template Template to register
|
||||
*/
|
||||
private static void registerTemplateHelper(final AzureVMAgentTemplate template) {
|
||||
String cloudName = AzureUtil.getCloudName(template.getAzureCloud().getSubscriptionId());
|
||||
String cloudName = "<unknown>";
|
||||
AzureCredentials.ServicePrincipal sp = template.getAzureCloud().getServicePrincipal();
|
||||
if(sp != null)
|
||||
cloudName = AzureUtil.getCloudName(sp.subscriptionId.getPlainText());
|
||||
LOGGER.log(Level.INFO, "AzureVMCloudVerificationTask: registerTemplateHelper: Registering template {0} on {1} for verification",
|
||||
new Object [] { template.getTemplateName(), cloudName });
|
||||
if (cloudTemplates == null) {
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
*/
|
||||
package com.microsoft.azure;
|
||||
|
||||
import com.cloudbees.plugins.credentials.CredentialsMatchers;
|
||||
import com.cloudbees.plugins.credentials.CredentialsProvider;
|
||||
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
|
||||
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import hudson.model.Descriptor.FormException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
@ -73,15 +77,18 @@ import com.microsoft.azure.exceptions.AzureCloudException;
|
|||
import com.microsoft.azure.exceptions.UnrecoverableCloudException;
|
||||
import com.microsoft.azure.retry.ExponentialRetryStrategy;
|
||||
import com.microsoft.azure.retry.NoRetryStrategy;
|
||||
import com.microsoft.azure.util.AzureCredentials;
|
||||
import com.microsoft.azure.util.AzureUserAgentFilter;
|
||||
import com.microsoft.azure.util.AzureUtil;
|
||||
import com.microsoft.azure.util.CleanUpAction;
|
||||
import com.microsoft.azure.util.Constants;
|
||||
import com.microsoft.azure.util.ExecutionEngine;
|
||||
import com.microsoft.azure.util.FailureStage;
|
||||
import hudson.security.ACL;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.logging.Level;
|
||||
|
@ -246,8 +253,11 @@ public class AzureVMManagementServiceDelegate {
|
|||
}
|
||||
|
||||
ObjectNode.class.cast(tmp.get("variables")).put("vmSize", template.getVirtualMachineSize());
|
||||
ObjectNode.class.cast(tmp.get("variables")).put("adminUsername", template.getAdminUserName());
|
||||
ObjectNode.class.cast(tmp.get("variables")).put("adminPassword", template.getAdminPassword());
|
||||
// Grab the username/pass
|
||||
StandardUsernamePasswordCredentials creds = AzureUtil.getCredentials(template.getCredentialsId());
|
||||
|
||||
ObjectNode.class.cast(tmp.get("variables")).put("adminUsername", creds.getUsername());
|
||||
ObjectNode.class.cast(tmp.get("variables")).put("adminPassword", creds.getPassword().getPlainText());
|
||||
|
||||
if (StringUtils.isNotBlank(template.getStorageAccountName())) {
|
||||
ObjectNode.class.cast(tmp.get("variables")).put("storageAccountName", template.getStorageAccountName());
|
||||
|
@ -375,7 +385,7 @@ public class AzureVMManagementServiceDelegate {
|
|||
azureAgent.setSshPort(Constants.DEFAULT_SSH_PORT);
|
||||
|
||||
LOGGER.log(Level.INFO, "Azure agent details:\nnodeName{0}\nadminUserName={1}\nshutdownOnIdle={2}\nretentionTimeInMin={3}\nlabels={4}",
|
||||
new Object[] { azureAgent.getNodeName(), azureAgent.getAdminUserName(), azureAgent.isShutdownOnIdle(),
|
||||
new Object[] { azureAgent.getNodeName(), azureAgent.getVMCredentialsId(), azureAgent.isShutdownOnIdle(),
|
||||
azureAgent.getRetentionTimeInMin(), azureAgent.getLabelString()});
|
||||
}
|
||||
|
||||
|
@ -459,21 +469,17 @@ public class AzureVMManagementServiceDelegate {
|
|||
template.getUseAgentAlwaysIfAvail(),
|
||||
template.getLabels(),
|
||||
template.getAzureCloud().getDisplayName(),
|
||||
template.getAdminUserName(),
|
||||
template.getCredentialsId(),
|
||||
null,
|
||||
null,
|
||||
template.getAdminPassword(),
|
||||
template.getJvmOptions(),
|
||||
template.isShutdownOnIdle(),
|
||||
false,
|
||||
deploymentName,
|
||||
template.getRetentionTimeInMin(),
|
||||
template.getInitScript(),
|
||||
azureCloud.getSubscriptionId(),
|
||||
azureCloud.getClientId(),
|
||||
azureCloud.getClientSecret(),
|
||||
azureCloud.getOauth2TokenEndpoint(),
|
||||
azureCloud.getServiceManagementURL(),
|
||||
azureCloud.getAzureCredentialsId(),
|
||||
azureCloud.getServicePrincipal(),
|
||||
template.getAgentLaunchMethod(),
|
||||
CleanUpAction.DEFAULT,
|
||||
null,
|
||||
|
@ -600,33 +606,19 @@ public class AzureVMManagementServiceDelegate {
|
|||
/**
|
||||
* Validates certificate configuration.
|
||||
*
|
||||
* @param subscriptionId
|
||||
* @param clientId
|
||||
* @param oauth2TokenEndpoint
|
||||
* @param clientSecret
|
||||
* @param serviceManagementURL
|
||||
* @param servicePrincipal
|
||||
* @param resourceGroupName
|
||||
* @return
|
||||
*/
|
||||
public static String verifyConfiguration(
|
||||
final String subscriptionId,
|
||||
final String clientId,
|
||||
final String clientSecret,
|
||||
final String oauth2TokenEndpoint,
|
||||
final String serviceManagementURL,
|
||||
final AzureCredentials.ServicePrincipal servicePrincipal,
|
||||
final String resourceGroupName) {
|
||||
if (StringUtils.isBlank(subscriptionId)
|
||||
|| StringUtils.isBlank(clientId)
|
||||
|| StringUtils.isBlank(oauth2TokenEndpoint)
|
||||
|| StringUtils.isBlank(clientSecret)
|
||||
|| StringUtils.isBlank(resourceGroupName)) {
|
||||
|
||||
if (servicePrincipal.isBlank() || StringUtils.isBlank(resourceGroupName)) {
|
||||
return Messages.Azure_GC_Template_Val_Profile_Missing();
|
||||
} else {
|
||||
try {
|
||||
// Load up the configuration now and do a live verification
|
||||
Configuration config = ServiceDelegateHelper.loadConfiguration(
|
||||
subscriptionId, clientId, clientSecret, oauth2TokenEndpoint, serviceManagementURL);
|
||||
// Load up the configuration now and do a live verification
|
||||
Configuration config = ServiceDelegateHelper.loadConfiguration(servicePrincipal);
|
||||
|
||||
if (!verifyConfiguration(config, resourceGroupName).equals(Constants.OP_SUCCESS)) {
|
||||
return Messages.Azure_GC_Template_Val_Profile_Err();
|
||||
|
@ -986,11 +978,7 @@ public class AzureVMManagementServiceDelegate {
|
|||
/**
|
||||
* Verifies template configuration by making server calls if needed.
|
||||
*
|
||||
* @param subscriptionId
|
||||
* @param clientId
|
||||
* @param clientSecret
|
||||
* @param oauth2TokenEndpoint
|
||||
* @param serviceManagementURL
|
||||
* @param servicePrincipal
|
||||
* @param templateName
|
||||
* @param labels
|
||||
* @param location
|
||||
|
@ -1005,23 +993,17 @@ public class AzureVMManagementServiceDelegate {
|
|||
* @param imageVersion
|
||||
* @param agentLaunchMethod
|
||||
* @param initScript
|
||||
* @param adminUserName
|
||||
* @param adminPassword
|
||||
* @param credentialsId
|
||||
* @param virtualNetworkName
|
||||
* @param subnetName
|
||||
* @param retentionTimeInMin
|
||||
* @param templateStatus
|
||||
* @param jvmOptions
|
||||
* @param returnOnSingleError
|
||||
* @param resourceGroupName
|
||||
* @return
|
||||
*/
|
||||
public static List<String> verifyTemplate(
|
||||
final String subscriptionId,
|
||||
final String clientId,
|
||||
final String clientSecret,
|
||||
final String oauth2TokenEndpoint,
|
||||
final String serviceManagementURL,
|
||||
final AzureCredentials.ServicePrincipal servicePrincipal,
|
||||
final String templateName,
|
||||
final String labels,
|
||||
final String location,
|
||||
|
@ -1036,8 +1018,7 @@ public class AzureVMManagementServiceDelegate {
|
|||
final String imageVersion,
|
||||
final String agentLaunchMethod,
|
||||
final String initScript,
|
||||
final String adminUserName,
|
||||
final String adminPassword,
|
||||
final String credentialsId,
|
||||
final String virtualNetworkName,
|
||||
final String subnetName,
|
||||
final String retentionTimeInMin,
|
||||
|
@ -1050,8 +1031,7 @@ public class AzureVMManagementServiceDelegate {
|
|||
|
||||
// Load configuration
|
||||
try {
|
||||
config = ServiceDelegateHelper.loadConfiguration(
|
||||
subscriptionId, clientId, clientSecret, oauth2TokenEndpoint, serviceManagementURL);
|
||||
config = ServiceDelegateHelper.loadConfiguration(servicePrincipal);
|
||||
String validationResult;
|
||||
|
||||
// Verify basic info about the template
|
||||
|
@ -1070,6 +1050,14 @@ public class AzureVMManagementServiceDelegate {
|
|||
}
|
||||
|
||||
//verify password
|
||||
String adminPassword="";
|
||||
try {
|
||||
StandardUsernamePasswordCredentials creds = AzureUtil.getCredentials(credentialsId);
|
||||
adminPassword = creds.getPassword().getPlainText();
|
||||
} catch(AzureCloudException e) {
|
||||
LOGGER.log(Level.SEVERE, "Could not load the VM credentials", e);
|
||||
}
|
||||
|
||||
validationResult = verifyAdminPassword(adminPassword);
|
||||
addValidationResultIfFailed(validationResult, errors);
|
||||
if (returnOnSingleError && errors.size() > 0) {
|
||||
|
@ -1089,7 +1077,7 @@ public class AzureVMManagementServiceDelegate {
|
|||
return errors;
|
||||
}
|
||||
|
||||
validationResult = verifyLocation(location, serviceManagementURL);
|
||||
validationResult = verifyLocation(location, servicePrincipal.serviceManagementURL);
|
||||
addValidationResultIfFailed(validationResult, errors);
|
||||
if (returnOnSingleError && errors.size() > 0) {
|
||||
return errors;
|
||||
|
|
|
@ -32,6 +32,7 @@ import com.microsoft.windowsazure.management.ManagementClient;
|
|||
import com.microsoft.windowsazure.management.ManagementService;
|
||||
import com.microsoft.azure.exceptions.AzureCloudException;
|
||||
import com.microsoft.azure.exceptions.UnrecoverableCloudException;
|
||||
import com.microsoft.azure.util.AzureCredentials;
|
||||
import com.microsoft.azure.util.AzureUserAgentFilter;
|
||||
import com.microsoft.azure.util.TokenCache;
|
||||
import hudson.slaves.Cloud;
|
||||
|
@ -51,12 +52,7 @@ public class ServiceDelegateHelper {
|
|||
|
||||
public static Configuration getConfiguration(final AzureVMCloud cloud) throws AzureCloudException {
|
||||
try {
|
||||
return loadConfiguration(
|
||||
cloud.getSubscriptionId(),
|
||||
cloud.getClientId(),
|
||||
cloud.getClientSecret(),
|
||||
cloud.getOauth2TokenEndpoint(),
|
||||
cloud.getServiceManagementURL());
|
||||
return loadConfiguration(cloud.getServicePrincipal());
|
||||
} catch (AzureCloudException e) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"AzureVMManagementServiceDelegate: getConfiguration: Failure loading configuration", e);
|
||||
|
@ -66,12 +62,7 @@ public class ServiceDelegateHelper {
|
|||
|
||||
public static Configuration getConfiguration(final AzureVMAgent agent) throws AzureCloudException {
|
||||
try {
|
||||
return loadConfiguration(
|
||||
agent.getSubscriptionId(),
|
||||
agent.getClientId(),
|
||||
agent.getClientSecret(),
|
||||
agent.getOauth2TokenEndpoint(),
|
||||
agent.getManagementURL());
|
||||
return loadConfiguration(agent.getServicePrincipal());
|
||||
} catch (AzureCloudException e) {
|
||||
// let's assume no updated information into the agent instance
|
||||
LOGGER.log(Level.INFO, "Missing connection with agent {0}", agent.getNodeName());
|
||||
|
@ -98,31 +89,18 @@ public class ServiceDelegateHelper {
|
|||
public static Configuration getConfiguration(final AzureVMAgentTemplate template) throws AzureCloudException {
|
||||
final AzureVMCloud azureCloud = template.getAzureCloud();
|
||||
|
||||
return loadConfiguration(
|
||||
azureCloud.getSubscriptionId(),
|
||||
azureCloud.getClientId(),
|
||||
azureCloud.getClientSecret(),
|
||||
azureCloud.getOauth2TokenEndpoint(),
|
||||
azureCloud.getServiceManagementURL());
|
||||
return loadConfiguration(azureCloud.getServicePrincipal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads configuration object..
|
||||
*
|
||||
* @param subscriptionId
|
||||
* @param clientId
|
||||
* @param clientSecret
|
||||
* @param oauth2TokenEndpoint
|
||||
* @param serviceManagementURL
|
||||
* @param servicePrincipal
|
||||
* @return
|
||||
* @throws AzureCloudException
|
||||
*/
|
||||
public static Configuration loadConfiguration(
|
||||
final String subscriptionId,
|
||||
final String clientId,
|
||||
final String clientSecret,
|
||||
final String oauth2TokenEndpoint,
|
||||
final String serviceManagementURL)
|
||||
final AzureCredentials.ServicePrincipal servicePrincipal)
|
||||
throws AzureCloudException {
|
||||
|
||||
// Azure libraries are internally using ServiceLoader.load(...) method which uses context classloader and
|
||||
|
@ -132,9 +110,7 @@ public class ServiceDelegateHelper {
|
|||
Thread.currentThread().setContextClassLoader(AzureVMManagementServiceDelegate.class.getClassLoader());
|
||||
|
||||
try {
|
||||
final Configuration config = TokenCache.getInstance(
|
||||
subscriptionId, clientId, clientSecret, oauth2TokenEndpoint, serviceManagementURL).get().
|
||||
getConfiguration();
|
||||
final Configuration config = TokenCache.getInstance(servicePrincipal).get().getConfiguration();
|
||||
|
||||
return config;
|
||||
} finally {
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2016 clguiman.
|
||||
/*
|
||||
Copyright 2016 Microsoft, 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.microsoft.azure.exceptions;
|
||||
|
||||
public class AzureCredentialsValidationException extends Exception {
|
||||
|
||||
public AzureCredentialsValidationException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AzureCredentialsValidationException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public AzureCredentialsValidationException(final String msg, final Exception excep) {
|
||||
super(msg, excep);
|
||||
}
|
||||
|
||||
public AzureCredentialsValidationException(final Exception excep) {
|
||||
super(excep);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -8157417759456046943L;
|
||||
|
||||
}
|
|
@ -15,6 +15,10 @@
|
|||
*/
|
||||
package com.microsoft.azure.remote;
|
||||
|
||||
import com.cloudbees.plugins.credentials.CredentialsMatchers;
|
||||
import com.cloudbees.plugins.credentials.CredentialsProvider;
|
||||
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
|
||||
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
|
||||
import com.jcraft.jsch.ChannelExec;
|
||||
import com.jcraft.jsch.ChannelSftp;
|
||||
import com.jcraft.jsch.JSch;
|
||||
|
@ -25,6 +29,8 @@ import com.microsoft.azure.AzureVMAgent;
|
|||
import com.microsoft.azure.AzureVMComputer;
|
||||
import com.microsoft.azure.AzureVMAgentTemplate;
|
||||
import com.microsoft.azure.Messages;
|
||||
import com.microsoft.azure.exceptions.AzureCloudException;
|
||||
import com.microsoft.azure.util.AzureUtil;
|
||||
import com.microsoft.azure.util.CleanUpAction;
|
||||
import com.microsoft.azure.util.Constants;
|
||||
import com.microsoft.azure.util.FailureStage;
|
||||
|
@ -33,6 +39,7 @@ import hudson.model.Descriptor;
|
|||
import hudson.model.TaskListener;
|
||||
import hudson.remoting.Channel;
|
||||
import hudson.remoting.Channel.Listener;
|
||||
import hudson.security.ACL;
|
||||
import hudson.slaves.ComputerLauncher;
|
||||
import hudson.slaves.OfflineCause;
|
||||
import hudson.slaves.SlaveComputer;
|
||||
|
@ -44,6 +51,7 @@ import java.io.OutputStream;
|
|||
import java.io.PrintStream;
|
||||
import java.net.ConnectException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collections;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import jenkins.model.Jenkins;
|
||||
|
@ -134,8 +142,11 @@ public class AzureVMAgentSSHLauncher extends ComputerLauncher {
|
|||
// Execute initialization script
|
||||
// Make sure to change file permission for execute if needed. TODO: need to test
|
||||
|
||||
// Grab the username/pass
|
||||
StandardUsernamePasswordCredentials creds = AzureUtil.getCredentials(agent.getVMCredentialsId());
|
||||
|
||||
String command = "sh " + remoteInitFileName;
|
||||
int exitStatus = executeRemoteCommand(session, command, logger, agent.getExecuteInitScriptAsRoot(), agent.getAdminPassword());
|
||||
int exitStatus = executeRemoteCommand(session, command, logger, agent.getExecuteInitScriptAsRoot(), creds.getPassword().getPlainText());
|
||||
if (exitStatus != 0) {
|
||||
if (agent.getDoNotUseMachineIfInitFails()) {
|
||||
LOGGER.log(Level.SEVERE, "AzureVMAgentSSHLauncher: launch: init script failed: exit code={0} (marking agent for deletion)", exitStatus);
|
||||
|
@ -234,8 +245,6 @@ public class AzureVMAgentSSHLauncher extends ComputerLauncher {
|
|||
new Object[] { dnsName, sshPort, e.getMessage() });
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void copyFileToRemote(Session jschSession, InputStream stream, String remotePath) throws Exception {
|
||||
|
@ -374,7 +383,10 @@ public class AzureVMAgentSSHLauncher extends ComputerLauncher {
|
|||
while (true) {
|
||||
currRetryCount++;
|
||||
try {
|
||||
session = getRemoteSession(agent.getAdminUserName(), agent.getAdminPassword(), agent.getPublicDNSName(),
|
||||
// Grab the username/pass
|
||||
StandardUsernamePasswordCredentials creds = AzureUtil.getCredentials(agent.getVMCredentialsId());
|
||||
|
||||
session = getRemoteSession(creds.getUsername(), creds.getPassword().getPlainText(), agent.getPublicDNSName(),
|
||||
agent.getSshPort());
|
||||
LOGGER.info("AzureVMAgentSSHLauncher: connectToSsh: Got remote connection");
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import com.microsoft.aad.adal4j.AuthenticationResult;
|
|||
import com.microsoft.windowsazure.Configuration;
|
||||
import com.microsoft.windowsazure.management.configuration.ManagementConfiguration;
|
||||
import com.microsoft.azure.exceptions.AzureCloudException;
|
||||
import hudson.util.Secret;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.net.URI;
|
||||
|
@ -27,21 +28,21 @@ import java.util.Date;
|
|||
|
||||
public class AccessToken implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
private final String subscriptionId;
|
||||
private final Secret subscriptionId;
|
||||
|
||||
private final String serviceManagementUrl;
|
||||
|
||||
private final String token;
|
||||
private final Secret token;
|
||||
|
||||
private final long expiration;
|
||||
|
||||
AccessToken(
|
||||
final String subscriptionId, final String serviceManagementUrl, final AuthenticationResult authres) {
|
||||
this.subscriptionId = subscriptionId;
|
||||
this.subscriptionId = Secret.fromString(subscriptionId);
|
||||
this.serviceManagementUrl = serviceManagementUrl;
|
||||
this.token = authres.getAccessToken();
|
||||
this.token = Secret.fromString(authres.getAccessToken());
|
||||
// In the 0.9.4 version of the SDK, expiresOn is the number of seconds till expire
|
||||
this.expiration = System.currentTimeMillis() + authres.getExpiresOn() * 1000;
|
||||
}
|
||||
|
@ -51,8 +52,8 @@ public class AccessToken implements Serializable {
|
|||
return ManagementConfiguration.configure(
|
||||
null,
|
||||
new URI(serviceManagementUrl),
|
||||
subscriptionId,
|
||||
token);
|
||||
subscriptionId.getPlainText(),
|
||||
token.getPlainText());
|
||||
} catch (URISyntaxException e) {
|
||||
throw new AzureCloudException("The syntax of the Url in the publish settings file is incorrect.", e);
|
||||
} catch (IOException e) {
|
||||
|
@ -68,12 +69,8 @@ public class AccessToken implements Serializable {
|
|||
return expiration < System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return token;
|
||||
return token.getPlainText();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
Copyright 2016 Microsoft, 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.microsoft.azure.util;
|
||||
|
||||
import com.cloudbees.plugins.credentials.CredentialsMatchers;
|
||||
import com.cloudbees.plugins.credentials.CredentialsProvider;
|
||||
import com.cloudbees.plugins.credentials.CredentialsScope;
|
||||
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
|
||||
import com.cloudbees.plugins.credentials.impl.BaseStandardCredentials;
|
||||
import com.microsoft.azure.AzureVMManagementServiceDelegate;
|
||||
import com.microsoft.azure.Messages;
|
||||
import com.microsoft.azure.exceptions.AzureCredentialsValidationException;
|
||||
import hudson.Extension;
|
||||
import hudson.security.ACL;
|
||||
import hudson.util.FormValidation;
|
||||
import hudson.util.Secret;
|
||||
import java.util.Collections;
|
||||
import jenkins.model.Jenkins;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.kohsuke.stapler.DataBoundConstructor;
|
||||
import org.kohsuke.stapler.QueryParameter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author clguiman
|
||||
*/
|
||||
public class AzureCredentials extends BaseStandardCredentials {
|
||||
|
||||
public static class ServicePrincipal {
|
||||
|
||||
public final Secret subscriptionId;
|
||||
public final Secret clientId;
|
||||
public final Secret clientSecret;
|
||||
public final Secret oauth2TokenEndpoint;
|
||||
public final String serviceManagementURL;
|
||||
|
||||
public ServicePrincipal(
|
||||
String subscriptionId,
|
||||
String clientId,
|
||||
String clientSecret,
|
||||
String oauth2TokenEndpoint,
|
||||
String serviceManagementURL) {
|
||||
this.subscriptionId = Secret.fromString(subscriptionId);
|
||||
this.clientId = Secret.fromString(clientId);
|
||||
this.clientSecret = Secret.fromString(clientSecret);
|
||||
this.oauth2TokenEndpoint = Secret.fromString(oauth2TokenEndpoint);
|
||||
this.serviceManagementURL = StringUtils.isBlank(serviceManagementURL)
|
||||
? Constants.DEFAULT_MANAGEMENT_URL
|
||||
: serviceManagementURL;
|
||||
}
|
||||
|
||||
public ServicePrincipal() {
|
||||
this.subscriptionId = Secret.fromString("");
|
||||
this.clientId = Secret.fromString("");
|
||||
this.clientSecret = Secret.fromString("");
|
||||
this.oauth2TokenEndpoint = Secret.fromString("");
|
||||
this.serviceManagementURL = Constants.DEFAULT_MANAGEMENT_URL;
|
||||
}
|
||||
|
||||
public boolean isBlank() {
|
||||
return StringUtils.isBlank(subscriptionId.getPlainText())
|
||||
|| StringUtils.isBlank(clientId.getPlainText())
|
||||
|| StringUtils.isBlank(oauth2TokenEndpoint.getPlainText())
|
||||
|| StringUtils.isBlank(clientSecret.getPlainText());
|
||||
}
|
||||
|
||||
public void Validate(String resourceGroupName) throws AzureCredentialsValidationException {
|
||||
if (StringUtils.isBlank(subscriptionId.getPlainText())) {
|
||||
throw new AzureCredentialsValidationException("Error: Subscription ID is missing");
|
||||
}
|
||||
if (StringUtils.isBlank(clientId.getPlainText())) {
|
||||
throw new AzureCredentialsValidationException("Error: Native Client ID is missing");
|
||||
}
|
||||
if (StringUtils.isBlank(clientSecret.getPlainText())) {
|
||||
throw new AzureCredentialsValidationException("Error: Azure Password is missing");
|
||||
}
|
||||
if (StringUtils.isBlank(oauth2TokenEndpoint.getPlainText())) {
|
||||
throw new AzureCredentialsValidationException("Error: OAuth 2.0 Token Endpoint is missing");
|
||||
}
|
||||
|
||||
String response = AzureVMManagementServiceDelegate.verifyConfiguration(this,resourceGroupName);
|
||||
if (!Constants.OP_SUCCESS.equalsIgnoreCase(response))
|
||||
throw new AzureCredentialsValidationException(response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final ServicePrincipal data;
|
||||
|
||||
@DataBoundConstructor
|
||||
public AzureCredentials(
|
||||
CredentialsScope scope,
|
||||
String id,
|
||||
String description,
|
||||
String subscriptionId,
|
||||
String clientId,
|
||||
String clientSecret,
|
||||
String oauth2TokenEndpoint,
|
||||
String serviceManagementURL) {
|
||||
super(scope, id, description);
|
||||
data = new ServicePrincipal(subscriptionId, clientId, clientSecret, oauth2TokenEndpoint, serviceManagementURL);
|
||||
}
|
||||
|
||||
public static AzureCredentials.ServicePrincipal getServicePrincipal(final String credentialsId) {
|
||||
AzureCredentials creds = CredentialsMatchers.firstOrNull(
|
||||
CredentialsProvider.lookupCredentials(AzureCredentials.class, Jenkins.getInstance(), ACL.SYSTEM, Collections.<DomainRequirement>emptyList()),
|
||||
CredentialsMatchers.withId(credentialsId));
|
||||
if (creds == null) {
|
||||
return new AzureCredentials.ServicePrincipal();
|
||||
}
|
||||
return creds.data;
|
||||
}
|
||||
|
||||
public String getSubscriptionId() {
|
||||
return data.subscriptionId.getEncryptedValue();
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return data.clientId.getEncryptedValue();
|
||||
}
|
||||
|
||||
public String getClientSecret() {
|
||||
return data.clientSecret.getEncryptedValue();
|
||||
}
|
||||
|
||||
public String getOauth2TokenEndpoint() {
|
||||
return data.oauth2TokenEndpoint.getEncryptedValue();
|
||||
}
|
||||
|
||||
public String getServiceManagementURL() {
|
||||
return data.serviceManagementURL;
|
||||
}
|
||||
|
||||
@Extension
|
||||
public static class DescriptorImpl extends BaseStandardCredentialsDescriptor {
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Microsoft Azure VM Agents";
|
||||
}
|
||||
|
||||
public String getDefaultserviceManagementURL() {
|
||||
return Constants.DEFAULT_MANAGEMENT_URL;
|
||||
}
|
||||
|
||||
public FormValidation doVerifyConfiguration(
|
||||
@QueryParameter String subscriptionId,
|
||||
@QueryParameter String clientId,
|
||||
@QueryParameter String clientSecret,
|
||||
@QueryParameter String oauth2TokenEndpoint,
|
||||
@QueryParameter String serviceManagementURL) {
|
||||
|
||||
AzureCredentials.ServicePrincipal servicePrincipal = new AzureCredentials.ServicePrincipal(subscriptionId, clientId, clientSecret, oauth2TokenEndpoint, serviceManagementURL);
|
||||
try {
|
||||
servicePrincipal.Validate(Constants.DEFAULT_RESOURCE_GROUP_NAME);
|
||||
} catch (AzureCredentialsValidationException e) {
|
||||
return FormValidation.error(e.getMessage());
|
||||
}
|
||||
|
||||
return FormValidation.ok(Messages.Azure_Config_Success());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -15,9 +15,17 @@
|
|||
*/
|
||||
package com.microsoft.azure.util;
|
||||
|
||||
import com.cloudbees.plugins.credentials.CredentialsMatchers;
|
||||
import com.cloudbees.plugins.credentials.CredentialsProvider;
|
||||
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
|
||||
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
|
||||
import com.microsoft.azure.exceptions.AzureCloudException;
|
||||
import hudson.security.ACL;
|
||||
import java.text.Format;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import jenkins.model.Jenkins;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
public class AzureUtil {
|
||||
|
@ -342,4 +350,18 @@ public class AzureUtil {
|
|||
Constants.VM_NAME_HASH_LENGTH, numberOfDigits),
|
||||
shortenedDeploymentHash);
|
||||
}
|
||||
|
||||
public static StandardUsernamePasswordCredentials getCredentials(String credentialsId) throws AzureCloudException {
|
||||
// Grab the pass
|
||||
StandardUsernamePasswordCredentials creds = CredentialsMatchers.firstOrNull(CredentialsProvider.lookupCredentials(
|
||||
StandardUsernamePasswordCredentials.class, Jenkins.getInstance(), ACL.SYSTEM,
|
||||
Collections.<DomainRequirement>emptyList()),
|
||||
CredentialsMatchers.withId(credentialsId));
|
||||
|
||||
if (creds == null) {
|
||||
throw new AzureCloudException("Could not find credentials with id: " + credentialsId);
|
||||
}
|
||||
|
||||
return creds;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,64 +47,37 @@ public class TokenCache {
|
|||
private static final Object tsafe = new Object();
|
||||
|
||||
private static TokenCache cache = null;
|
||||
|
||||
protected final String subscriptionId;
|
||||
|
||||
protected final String clientId;
|
||||
|
||||
protected final String clientSecret;
|
||||
|
||||
protected final String oauth2TokenEndpoint;
|
||||
|
||||
protected final String serviceManagementURL;
|
||||
|
||||
protected final AzureCredentials.ServicePrincipal credentials;
|
||||
|
||||
private final String path;
|
||||
|
||||
public static TokenCache getInstance(
|
||||
final String subscriptionId,
|
||||
final String clientId,
|
||||
final String clientSecret,
|
||||
final String oauth2TokenEndpoint,
|
||||
final String serviceManagementURL) {
|
||||
public static TokenCache getInstance(final AzureCredentials.ServicePrincipal servicePrincipal) {
|
||||
synchronized (tsafe) {
|
||||
if (cache == null) {
|
||||
cache = new TokenCache(
|
||||
subscriptionId, clientId, clientSecret, oauth2TokenEndpoint, serviceManagementURL);
|
||||
} else if (cache.subscriptionId == null || !cache.subscriptionId.equals(subscriptionId)
|
||||
|| cache.clientId == null || !cache.clientId.equals(clientId)
|
||||
|| cache.clientSecret == null || !cache.clientSecret.equals(clientSecret)
|
||||
|| cache.oauth2TokenEndpoint == null || !cache.oauth2TokenEndpoint.equals(oauth2TokenEndpoint)
|
||||
|| cache.serviceManagementURL == null || !cache.serviceManagementURL.equals(serviceManagementURL)) {
|
||||
cache = new TokenCache(servicePrincipal);
|
||||
} else if (cache.credentials == null
|
||||
|| cache.credentials.subscriptionId == null || !cache.credentials.subscriptionId.equals(servicePrincipal.subscriptionId)
|
||||
|| cache.credentials.clientId == null || !cache.credentials.clientId.equals(servicePrincipal.clientId)
|
||||
|| cache.credentials.clientSecret == null || !cache.credentials.clientSecret.equals(servicePrincipal.clientSecret)
|
||||
|| cache.credentials.oauth2TokenEndpoint == null || !cache.credentials.oauth2TokenEndpoint.equals(servicePrincipal.oauth2TokenEndpoint)
|
||||
|| cache.credentials.serviceManagementURL == null || !cache.credentials.serviceManagementURL.equals(servicePrincipal.serviceManagementURL)) {
|
||||
cache.clear();
|
||||
cache = new TokenCache(
|
||||
subscriptionId, clientId, clientSecret, oauth2TokenEndpoint, serviceManagementURL);
|
||||
cache = new TokenCache(servicePrincipal);
|
||||
}
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
private TokenCache(
|
||||
final String subscriptionId,
|
||||
final String clientId,
|
||||
final String clientSecret,
|
||||
final String oauth2TokenEndpoint,
|
||||
final String serviceManagementURL) {
|
||||
private TokenCache(final AzureCredentials.ServicePrincipal servicePrincipal) {
|
||||
LOGGER.log(Level.FINEST, "TokenCache: TokenCache: Instantiate new cache manager");
|
||||
|
||||
this.subscriptionId = subscriptionId;
|
||||
this.clientId = clientId;
|
||||
this.clientSecret = clientSecret;
|
||||
this.oauth2TokenEndpoint = oauth2TokenEndpoint;
|
||||
this.credentials = servicePrincipal;
|
||||
|
||||
// Compute the cloud name
|
||||
String cloudName = AzureUtil.getCloudName(subscriptionId);
|
||||
|
||||
if (StringUtils.isBlank(serviceManagementURL)) {
|
||||
this.serviceManagementURL = Constants.DEFAULT_MANAGEMENT_URL;
|
||||
} else {
|
||||
this.serviceManagementURL = serviceManagementURL;
|
||||
}
|
||||
String cloudName = "<unknown";
|
||||
if(credentials != null)
|
||||
cloudName =AzureUtil.getCloudName(credentials.subscriptionId.getPlainText());
|
||||
|
||||
final String home = Jenkins.getInstance().root.getPath();
|
||||
|
||||
|
@ -199,13 +172,12 @@ public class TokenCache {
|
|||
AuthenticationResult authres = null;
|
||||
|
||||
try {
|
||||
LOGGER.log(Level.FINEST, "TokenCache: getNewToken: Aquiring access token: \n\t{0}\n\t{1}\n\t{2}",
|
||||
new Object[] { oauth2TokenEndpoint, serviceManagementURL, clientId });
|
||||
LOGGER.log(Level.FINEST, "TokenCache: getNewToken: Aquiring access token:");
|
||||
|
||||
final ClientCredential credential = new ClientCredential(clientId, clientSecret);
|
||||
final ClientCredential credential = new ClientCredential(credentials.clientId.getPlainText(), credentials.clientSecret.getPlainText());
|
||||
|
||||
final Future<AuthenticationResult> future = new AuthenticationContext(oauth2TokenEndpoint, false, service).
|
||||
acquireToken(serviceManagementURL, credential, null);
|
||||
final Future<AuthenticationResult> future = new AuthenticationContext(credentials.oauth2TokenEndpoint.getPlainText(), false, service).
|
||||
acquireToken(credentials.serviceManagementURL, credential, null);
|
||||
|
||||
authres = future.get();
|
||||
} catch (MalformedURLException e) {
|
||||
|
@ -222,7 +194,7 @@ public class TokenCache {
|
|||
throw new AzureCloudException("Authentication result was null");
|
||||
}
|
||||
|
||||
final AccessToken token = new AccessToken(subscriptionId, serviceManagementURL, authres);
|
||||
final AccessToken token = new AccessToken(credentials.subscriptionId.getPlainText(), credentials.serviceManagementURL, authres);
|
||||
|
||||
writeTokenFile(token);
|
||||
return token;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:c="/lib/credentials" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<table width="100%">
|
||||
<f:section title="${%General_Configuration}">
|
||||
<f:entry title="${%Template_Name}" field="templateName" help="/plugin/azure-vm-agents-plugin/help-templateName.html">
|
||||
|
@ -67,6 +67,10 @@
|
|||
<f:select />
|
||||
</f:entry>
|
||||
|
||||
<f:entry title="${%Admin_Credentials}" field="credentialsId" help="/plugin/azure-vm-agents-plugin/help-credentials.html">
|
||||
<c:select expressionAllowed="false"/>
|
||||
</f:entry>
|
||||
|
||||
<f:section title="${%Initialization_Configuration}">
|
||||
<f:entry title="${%Init_Script}" field="initScript" help="/plugin/azure-vm-agents-plugin/help-initScript.html">
|
||||
<f:textarea />
|
||||
|
@ -80,14 +84,6 @@
|
|||
<f:checkbox default="true"/>
|
||||
</f:entry>
|
||||
</f:section>
|
||||
|
||||
<f:entry title="${%Username}" field="adminUserName" help="/plugin/azure-vm-agents-plugin/help-adminUserName.html">
|
||||
<f:textbox />
|
||||
</f:entry>
|
||||
|
||||
<f:entry title="${%Password}" field="adminPassword" help="/plugin/azure-vm-agents-plugin/help-adminPassword.html">
|
||||
<f:password />
|
||||
</f:entry>
|
||||
</f:section>
|
||||
|
||||
<f:advanced>
|
||||
|
@ -125,6 +121,6 @@
|
|||
</div>
|
||||
</f:entry>
|
||||
<f:validateButton title="${%Verify_Template}" progress="${%Verifying_Template_MSG}" method="verifyConfiguration"
|
||||
with="subscriptionId,clientId,clientSecret,oauth2TokenEndpoint,serviceManagementURL,resourceGroupName,templateName,labels,location,virtualMachineSize,storageAccountName,noOfParallelJobs,image,osType,imagePublisher,imageOffer,imageSku,imageVersion,agentLaunchMethod,initScript,adminUserName,adminPassword,virtualNetworkName,subnetName,retentionTimeInMin,jvmOptions" />
|
||||
with="azureCredentialsId,resourceGroupName,templateName,labels,location,virtualMachineSize,storageAccountName,noOfParallelJobs,image,osType,imagePublisher,imageOffer,imageSku,imageVersion,agentLaunchMethod,initScript,credentialsId,virtualNetworkName,subnetName,retentionTimeInMin,jvmOptions" />
|
||||
</table>
|
||||
</j:jelly>
|
||||
|
|
|
@ -27,8 +27,7 @@ Init_Script=Initialization Script
|
|||
Execute_Init_Script_As_Root=Run Initialization Script As Root (Linux Only)
|
||||
Do_Not_Use_Machine_If_Init_Fails=Don't Use VM If Initialization Script Fails (Linux Only)
|
||||
|
||||
Username=Username
|
||||
Password=Password
|
||||
Admin_Credentials=Admin Credentials
|
||||
Agent_Workspace=Agent Workspace
|
||||
JVM_Options=JVM Options
|
||||
|
||||
|
|
|
@ -1,27 +1,11 @@
|
|||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define"
|
||||
xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:c="/lib/credentials">
|
||||
|
||||
<f:section title="${%Azure_Profile_Configuration}">
|
||||
<f:entry title="${%Subscription_ID}" field="subscriptionId"
|
||||
help="/plugin/azure-vm-agents-plugin/help-subscriptionId.html">
|
||||
<f:password />
|
||||
<f:entry title="${%Azure_Credentials}" field="azureCredentialsId" help="/plugin/azure-vm-agents-plugin/help-azureCredentials.html">
|
||||
<c:select expressionAllowed="false"/>
|
||||
</f:entry>
|
||||
|
||||
<f:entry title="${%Client_Id}" field="clientId"
|
||||
help="/plugin/azure-vm-agents-plugin/help-clientId.html">
|
||||
<f:password />
|
||||
</f:entry>
|
||||
<f:entry title="${%Client_Secret}" field="clientSecret"
|
||||
help="/plugin/azure-vm-agents-plugin/help-clientSecret.html">
|
||||
<f:password />
|
||||
</f:entry>
|
||||
|
||||
<f:entry title="${%OAuth2_Token_Endpoint}" field="oauth2TokenEndpoint"
|
||||
help="/plugin/azure-vm-agents-plugin/help-oauth2TokenEndpoint.html">
|
||||
<f:password />
|
||||
</f:entry>
|
||||
|
||||
<f:entry title="${%Max_Virtual_Machines_Limit}" field="maxVirtualMachinesLimit" help="/plugin/azure-vm-agents-plugin/help-maxVirtualMachinesLimit.html">
|
||||
<f:textbox default="${descriptor.getDefaultMaxVMLimit()}" />
|
||||
</f:entry>
|
||||
|
@ -33,15 +17,8 @@
|
|||
<f:entry title="${%Resource_Group_Name}" field="resourceGroupName" help="/plugin/azure-vm-agents-plugin/help-resourceGroupName.html">
|
||||
<f:textbox default="${descriptor.getDefaultResourceGroupName()}" />
|
||||
</f:entry>
|
||||
|
||||
<f:advanced>
|
||||
<f:entry title="${%Service_Management_URL}" field="serviceManagementURL" help="/plugin/azure-vm-agents-plugin/help-serviceManagementURL.html">
|
||||
<f:textbox default="${descriptor.getDefaultserviceManagementURL()}" />
|
||||
</f:entry>
|
||||
</f:advanced>
|
||||
|
||||
<f:validateButton title="${%Verify_Configuration}" progress="${%Verifying}" method="verifyConfiguration"
|
||||
with="subscriptionId,clientId,clientSecret,oauth2TokenEndpoint,serviceManagementURL,resourceGroupName" />
|
||||
with="azureCredentialsId,resourceGroupName" />
|
||||
</f:section>
|
||||
|
||||
<f:entry title="${%Azure_Virtual_Machine_Template}" description="${%Azure_Virtual_Machine_Template_desc}">
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
Azure_Profile_Configuration=Azure Profile Configuration
|
||||
Azure_Credentials=Azure Credentials
|
||||
Subscription_ID=Subscription ID
|
||||
Client_Id=Client ID
|
||||
Client_Secret=Client Secret
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:st="jelly:stapler" xmlns:d="jelly:define">
|
||||
<j:set var="uniqueId" value="${h.generateId()}" />
|
||||
<f:entry title="${%Subscription ID}" field="subscriptionId" help="/plugin/azure-vm-agents-plugin/help-subscriptionId.html">
|
||||
<f:password />
|
||||
</f:entry>
|
||||
<f:entry title="${%Client ID}" field="clientId" help="/plugin/azure-vm-agents-plugin/help-clientId.html">
|
||||
<f:password />
|
||||
</f:entry>
|
||||
<f:entry title="${%Client Secret}" field="clientSecret" help="/plugin/azure-vm-agents-plugin/help-clientSecret.html">
|
||||
<f:password />
|
||||
</f:entry>
|
||||
<f:entry title="${%OAuth 2.0 Token Endpoint}" field="oauth2TokenEndpoint" help="/plugin/azure-vm-agents-plugin/help-oauth2TokenEndpoint.html">
|
||||
<f:password />
|
||||
</f:entry>
|
||||
<f:entry title="${%Management Service URL}" field="serviceManagementURL" help="/plugin/azure-vm-agents-plugin/help-serviceManagementURL.html">
|
||||
<f:textbox default="${descriptor.getDefaultserviceManagementURL()}"/>
|
||||
</f:entry>
|
||||
<st:include page="id-and-description" class="${descriptor.clazz}"/>
|
||||
<f:validateButton title="${%Verify Configuration}" progress="${%Verifying}" method="verifyConfiguration"
|
||||
with="subscriptionId,clientId,clientSecret,oauth2TokenEndpoint,serviceManagementURL" />
|
||||
</j:jelly>
|
|
@ -1,10 +0,0 @@
|
|||
<div>
|
||||
The password for the agent machine. Rules for the password:</br>
|
||||
1. The password must contain at least 8 characters.</br>
|
||||
2. The password cannot be longer than 123 characters.</br>
|
||||
3. The password must contain 3 of the following.</br>
|
||||
a) a lowercase character</br>
|
||||
b) an uppercase character</br>
|
||||
c) a number</br>
|
||||
d) one of the following special characters: !@#$%^&*.
|
||||
</div>
|
|
@ -1,3 +0,0 @@
|
|||
<div>
|
||||
Administrator user name for the agent.
|
||||
</div>
|
|
@ -0,0 +1,7 @@
|
|||
<div>
|
||||
The Service Principal credentials required to connect to your Azure account.
|
||||
<br />
|
||||
More information can be found here: <a target="_blank" href="https://azure.microsoft.com/en-us/documentation/articles/resource-group-authenticate-service-principal">https://azure.microsoft.com/en-us/documentation/articles/resource-group-authenticate-service-principal</a>
|
||||
<br />
|
||||
If you want to add an Azure credential click "Add" and select "Microsoft Azure VM Agents" from the Kind drop-down.
|
||||
</div>
|
|
@ -0,0 +1,3 @@
|
|||
<div>
|
||||
The credentials for the agent machine.
|
||||
</div>
|
Loading…
Reference in New Issue