Skip to content

Commit

Permalink
[JENKINS-42799] Support cloud statistics plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
ArchangelSDY committed May 31, 2017
1 parent 52a00cc commit 06d92b9
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 48 deletions.
13 changes: 9 additions & 4 deletions pom.xml
Expand Up @@ -86,7 +86,7 @@
<version>${azuresdk.version}</version>
<type>jar</type>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
Expand All @@ -102,13 +102,13 @@
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>

<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>azure-credentials</artifactId>
<version>${azure-credentials.version}</version>
</dependency>

<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
Expand Down Expand Up @@ -137,7 +137,7 @@
</exclusions>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
Expand Down Expand Up @@ -168,6 +168,11 @@
<artifactId>plain-credentials</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>cloud-stats</artifactId>
<version>0.11</version>
</dependency>
</dependencies>

<scm>
Expand Down
28 changes: 24 additions & 4 deletions src/main/java/com/microsoft/azure/vmagent/AzureVMAgent.java
@@ -1,12 +1,12 @@
/*
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.
Expand All @@ -32,20 +32,26 @@
import hudson.slaves.RetentionStrategy;
import hudson.util.FormValidation;
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.cloudstats.CloudStatistics;
import org.jenkinsci.plugins.cloudstats.ProvisioningActivity;
import org.jenkinsci.plugins.cloudstats.TrackedItem;
import org.jvnet.localizer.Localizable;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class AzureVMAgent extends AbstractCloudSlave {
public class AzureVMAgent extends AbstractCloudSlave implements TrackedItem {

private static final long serialVersionUID = -760014706860995557L;

private ProvisioningActivity.Id provisioningId;

private final String cloudName;

private final String vmCredentialsId;
Expand Down Expand Up @@ -157,6 +163,7 @@ public AzureVMAgent(
}

public AzureVMAgent(
final ProvisioningActivity.Id id,
final String name,
final String templateName,
final String nodeDescription,
Expand Down Expand Up @@ -214,6 +221,8 @@ public AzureVMAgent(
resourceGroupName,
executeInitScriptAsRoot,
doNotUseMachineIfInitFails);

this.provisioningId = id;
}

public String getCloudName() {
Expand Down Expand Up @@ -405,6 +414,11 @@ public boolean getDoNotUseMachineIfInitFails() {
protected void _terminate(final TaskListener arg0) throws IOException, InterruptedException {
//TODO: Check when this method is getting called and code accordingly
LOGGER.log(Level.INFO, "AzureVMAgent: _terminate: called for agent {0}", getNodeName());

ProvisioningActivity activity = CloudStatistics.get().getActivityFor(this);
if (activity != null) {
activity.enterIfNotAlready(ProvisioningActivity.Phase.COMPLETED);
}
}

@Override
Expand Down Expand Up @@ -494,6 +508,12 @@ public String toString() {
+ "\n]";
}

@Nullable
@Override
public ProvisioningActivity.Id getId() {
return provisioningId;
}

@Extension
public static final class AzureVMAgentDescriptor extends SlaveDescriptor {

Expand Down
75 changes: 48 additions & 27 deletions src/main/java/com/microsoft/azure/vmagent/AzureVMCloud.java
@@ -1,12 +1,12 @@
/*
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.
Expand All @@ -28,6 +28,24 @@
import com.microsoft.azure.vmagent.exceptions.AzureCloudException;
import com.microsoft.azure.vmagent.remote.AzureVMAgentSSHLauncher;
import com.microsoft.azure.vmagent.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import jenkins.model.Jenkins;

import org.jenkinsci.plugins.cloudstats.ProvisioningActivity;
import org.jenkinsci.plugins.cloudstats.TrackedPlannedNode;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

import hudson.Extension;
import hudson.init.InitMilestone;
import hudson.init.Initializer;
Expand All @@ -38,20 +56,11 @@
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import hudson.util.StreamTaskListener;
import jenkins.model.Jenkins;
import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class AzureVMCloud extends Cloud {

Expand All @@ -74,7 +83,7 @@ public class AzureVMCloud extends Cloud {
private transient List<AzureVMAgentTemplate> instTemplates;

private final int deploymentTimeout;

private static ExecutorService threadPool;

// True if the subscription has been verified.
Expand Down Expand Up @@ -155,14 +164,14 @@ private Object readResolve() {
vmTemplates = instTemplates;
instTemplates = null;
}

// Walk the list of templates and assign the parent cloud (which is transient).
ensureVmTemplateList();
for (AzureVMAgentTemplate template : vmTemplates) {
template.setAzureCloud(this);
}
}

return this;
}

Expand Down Expand Up @@ -204,7 +213,7 @@ public synchronized static ExecutorService getThreadPool() {
}
return AzureVMCloud.threadPool;
}

public int getMaxVirtualMachinesLimit() {
return maxVirtualMachinesLimit;
}
Expand Down Expand Up @@ -446,6 +455,7 @@ public AzureVMAgentTemplate getAzureAgentTemplate(final String name) {
* @throws Exception
*/
public AzureVMAgent createProvisionedAgent(
final ProvisioningActivity.Id provisioningId,
final AzureVMAgentTemplate template,
final String vmName,
final String deploymentName) throws Exception {
Expand Down Expand Up @@ -500,8 +510,8 @@ else if (state.equalsIgnoreCase("succeeded")) {

final VirtualMachine vm = azureClient.virtualMachines().getByGroup(resourceGroupName, resource);
final OperatingSystemTypes osType = vm.storageProfile().osDisk().osType();
AzureVMAgent newAgent = AzureVMManagementServiceDelegate.parseResponse(vmName, deploymentName, template, osType);

AzureVMAgent newAgent = AzureVMManagementServiceDelegate.parseResponse(provisioningId, vmName, deploymentName, template, osType);
AzureVMManagementServiceDelegate.setVirtualMachineDetails(newAgent, template);
return newAgent;
} else {
Expand All @@ -512,7 +522,7 @@ else if (state.equalsIgnoreCase("succeeded")) {
}
}
}

}
} while (triesLeft > 0);

Expand Down Expand Up @@ -542,17 +552,23 @@ public Collection<PlannedNode> provision(final Label label, int workLoad) {

if (agentNode != null && isNodeEligibleForReuse(agentNode, template)) {
LOGGER.log(Level.INFO, "AzureVMCloud: provision: agent computer eligible for reuse {0}", agentComputer.getName());

final ProvisioningActivity.Id provisioningId = new ProvisioningActivity.Id(this.name, template.getTemplateName());

try {
if (AzureVMManagementServiceDelegate.virtualMachineExists(agentNode)) {
numberOfAgents--;
plannedNodes.add(new PlannedNode(
template.getTemplateName(),

plannedNodes.add(new TrackedPlannedNode(
provisioningId,
template.getNoOfParallelJobs(),
Computer.threadPoolForRemoting.submit(new Callable<Node>() {

@Override
public Node call() throws Exception {
LOGGER.log(Level.INFO, "Found existing node, starting VM {0}", agentNode.
getNodeName());

AzureVMManagementServiceDelegate.startVirtualMachine(agentNode);
// set virtual machine details again
Thread.sleep(30 * 1000); // wait for 30 seconds
Expand All @@ -567,9 +583,10 @@ public Node call() throws Exception {
azureComputer.setAcceptingTasks(true);
agentNode.clearCleanUpAction();
agentNode.setEligibleForReuse(false);

return agentNode;
}
}), template.getNoOfParallelJobs()));
})));
}
} catch (Exception e) {
// Couldn't bring the node back online. Mark it
Expand Down Expand Up @@ -611,14 +628,17 @@ public AzureVMDeploymentInfo call() throws Exception {

for (int i = 0; i < numberOfNewAgents; i++) {
final int index = i;
plannedNodes.add(new PlannedNode(
template.getTemplateName(),
final ProvisioningActivity.Id provisioningId = new ProvisioningActivity.Id(this.name, template.getTemplateName());

plannedNodes.add(new TrackedPlannedNode(
provisioningId,
template.getNoOfParallelJobs(),
Computer.threadPoolForRemoting.submit(new Callable<Node>() {

@Override
public Node call() throws Exception {

// Wait for the future to complete
// Wait for the future to complete
AzureVMDeploymentInfo info = deploymentFuture.get();

final String deploymentName = info.getDeploymentName();
Expand All @@ -628,6 +648,7 @@ public Node call() throws Exception {
AzureVMAgent agent = null;
try {
agent = createProvisionedAgent(
provisioningId,
template,
vmName,
deploymentName);
Expand Down Expand Up @@ -683,7 +704,7 @@ public Node call() throws Exception {
}
return agent;
}
}), template.getNoOfParallelJobs()));
})));
}
// wait for deployment completion ant than check for created nodes
} catch (Exception e) {
Expand Down Expand Up @@ -800,7 +821,7 @@ public FormValidation doVerifyConfiguration(

if (StringUtils.isBlank(resourceGroupName)) {
resourceGroupName = Constants.DEFAULT_RESOURCE_GROUP_NAME;
}
}
AzureCredentials.ServicePrincipal credentials = AzureCredentials.getServicePrincipal(azureCredentialsId);
try {
credentials.validate();
Expand Down

0 comments on commit 06d92b9

Please sign in to comment.