Skip to content

Commit

Permalink
Show LRM actions on build page
Browse files Browse the repository at this point in the history
  • Loading branch information
mPokornyETM committed Jun 19, 2024
1 parent 861833e commit 8c01d45
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ public boolean start() throws Exception {

LockableResourcesManager lrm = LockableResourcesManager.get();
List<LockableResource> available = null;
LinkedHashMap<String, List<LockableResourceProperty>> resourceNames = new LinkedHashMap<>();
LinkedHashMap<String, List<LockableResourceProperty>> lockedResources = new LinkedHashMap<>();
synchronized (lrm.syncResources) {
List<String> resourceNames = new ArrayList<>();
for (LockStepResource resource : step.getResources()) {
List<String> resources = new ArrayList<>();
if (resource.resource != null) {
Expand All @@ -71,10 +72,16 @@ public boolean start() throws Exception {
logger);
}
resources.add(resource.resource);
resourceNames.addAll(resources);
} else {
resourceNames.add("N/A");
}
resourceHolderList.add(new LockableResourcesStruct(resources, resource.label, resource.quantity));

}

LockedResourcesBuildAction.updateAction(run, resourceNames, "try", step.toString());

// determine if there are enough resources available to proceed
available = lrm.getAvailableResources(resourceHolderList, logger, resourceSelectStrategy);
if (available == null || available.isEmpty()) {
Expand All @@ -95,10 +102,10 @@ public boolean start() throws Exception {
// since LockableResource contains transient variables, they cannot be correctly serialized
// hence we use their unique resource names and properties
for (LockableResource resource : available) {
resourceNames.put(resource.getName(), resource.getProperties());
lockedResources.put(resource.getName(), resource.getProperties());
}
}
LockStepExecution.proceed(resourceNames, getContext(), step.toString(), step.variable);
LockStepExecution.proceed(lockedResources, getContext(), step.toString(), step.variable);

return false;
}
Expand Down Expand Up @@ -166,11 +173,12 @@ public static void proceed(
}

try {

LockedResourcesBuildAction.updateAction(build, new ArrayList<>(lockedResources.keySet()));
List<String> resourceNames = new ArrayList<>(lockedResources.keySet());
final String resourceNamesAsString = String.join(",", lockedResources.keySet());
LockedResourcesBuildAction.updateAction(build, resourceNames, "acquired", resourceDescription);
PauseAction.endCurrentPause(node);
BodyInvoker bodyInvoker = context.newBodyInvoker()
.withCallback(new Callback(new ArrayList<>(lockedResources.keySet()), resourceDescription));
.withCallback(new Callback(resourceNames, resourceDescription));
if (variable != null && !variable.isEmpty()) {
// set the variable for the duration of the block
bodyInvoker.withContext(
Expand All @@ -180,8 +188,7 @@ public static void proceed(
@Override
public void expand(@NonNull EnvVars env) {
final LinkedHashMap<String, String> variables = new LinkedHashMap<>();
final String resourceNames = String.join(",", lockedResources.keySet());
variables.put(variable, resourceNames);
variables.put(variable, resourceNamesAsString);
int index = 0;
for (Entry<String, List<LockableResourceProperty>> lockResourceEntry :
lockedResources.entrySet()) {
Expand Down Expand Up @@ -222,9 +229,11 @@ private static final class Callback extends BodyExecutionCallback.TailCall {

@Override
protected void finished(StepContext context) throws Exception {
LockableResourcesManager.get().unlockNames(this.resourceNames, context.get(Run.class));
Run<?, ?> build = context.get(Run.class);
LockableResourcesManager.get().unlockNames(this.resourceNames, build);
LockedResourcesBuildAction.updateAction(build, this.resourceNames, "released", this.resourceDescription);
LockableResourcesManager.printLogs(
"Lock released on resource [" + resourceDescription + "]",
"Lock released on resource [" + this.resourceDescription + "]",
Level.FINE,
LOGGER,
context.get(TaskListener.class).getLogger());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public List<LockableResource> getReadOnlyResources() {
/** Get declared resources, means only defined in config file (xml or JCaC yaml). */
public List<LockableResource> getDeclaredResources() {
ArrayList<LockableResource> declaredResources = new ArrayList<>();
for (LockableResource r : this.getReadOnlyResources()) {
for (LockableResource r : this.getResources()) {
if (!r.isEphemeral() && !r.isNodeResource()) {
declaredResources.add(r);
}
Expand Down Expand Up @@ -165,7 +165,7 @@ public void setDeclaredResources(List<LockableResource> declaredResources) {
@Restricted(NoExternalUse.class)
public List<LockableResource> getResourcesFromProject(String fullName) {
List<LockableResource> matching = new ArrayList<>();
for (LockableResource r : this.getReadOnlyResources()) {
for (LockableResource r : this.getResources()) {
String rName = r.getQueueItemProject();
if (rName != null && rName.equals(fullName)) {
matching.add(r);
Expand All @@ -179,7 +179,7 @@ public List<LockableResource> getResourcesFromProject(String fullName) {
@Restricted(NoExternalUse.class)
public List<LockableResource> getResourcesFromBuild(Run<?, ?> build) {
List<LockableResource> matching = new ArrayList<>();
for (LockableResource r : this.getReadOnlyResources()) {
for (LockableResource r : this.getResources()) {
Run<?, ?> rBuild = r.getBuild();
if (rBuild != null && rBuild == build) {
matching.add(r);
Expand All @@ -198,10 +198,12 @@ public Boolean isValidLabel(@Nullable String label) {
return false;
}

for (LockableResource r : this.getReadOnlyResources()) {
if (r != null && r.isValidLabel(label)) {
return true;
}
synchronized (this.syncResources) {
for (LockableResource r : this.getResources()) {
if (r != null && r.isValidLabel(label)) {
return true;
}
}
}

return false;
Expand Down Expand Up @@ -326,8 +328,10 @@ public LockableResource fromName(@CheckForNull String resourceName) {

if (resourceName != null) {

for (LockableResource r : this.getReadOnlyResources()) {
if (resourceName.equals(r.getName())) return r;
synchronized (this.syncResources) {
for (LockableResource r : this.getResources()) {
if (resourceName.equals(r.getName())) return r;
}
}
} else {
LOGGER.warning("Internal failure, fromName is empty or null:" + getStack());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import hudson.model.Run;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.jenkins.plugins.lockableresources.LockableResource;
import org.jenkins.plugins.lockableresources.LockableResourcesManager;
Expand All @@ -30,14 +31,21 @@ public class LockedResourcesBuildAction implements Action {
// -------------------------------------------------------------------------
private final List<ResourcePOJO> lockedResources;

/** Object to synchronized operations over LRM */
private static final transient Object syncResources = new Object();

// -------------------------------------------------------------------------
public LockedResourcesBuildAction(List<ResourcePOJO> lockedResources) {
this.lockedResources = lockedResources;
synchronized (this.syncResources) {
this.lockedResources = lockedResources;
}
}

// -------------------------------------------------------------------------
public List<ResourcePOJO> getLockedResources() {
return lockedResources;
synchronized (this.syncResources) {
return lockedResources;
}
}

// -------------------------------------------------------------------------
Expand All @@ -61,28 +69,20 @@ public String getUrlName() {
// -------------------------------------------------------------------------
/** Adds *resourceNames* to *build*.
* When the action does not exists, will be created as well.
* When the resource has been used by this build just now, the counter will
* increased to eliminate multiple entries.
* Used in pipelines - lock() step
*/
@Restricted(NoExternalUse.class)
public static void updateAction(Run<?, ?> build, List<String> resourceNames) {
LockedResourcesBuildAction action = build.getAction(LockedResourcesBuildAction.class);
public static void updateAction(Run<?, ?> build, List<String> resourceNames, String action, String step) {
LockedResourcesBuildAction buildAction = build.getAction(LockedResourcesBuildAction.class);

if (action == null) {
if (buildAction == null) {
List<ResourcePOJO> resPojos = new ArrayList<>();
action = new LockedResourcesBuildAction(resPojos);
build.addAction(action);
buildAction = new LockedResourcesBuildAction(resPojos);
build.addAction(buildAction);
}

for (String name : resourceNames) {
LockableResource r = LockableResourcesManager.get().fromName(name);
if (r != null) {
action.add(new ResourcePOJO(r));
} else {
// probably a ephemeral resource has been deleted
action.add(new ResourcePOJO(name, ""));
}
buildAction.add(new ResourcePOJO(name, step, action));
}
}

Expand All @@ -92,13 +92,9 @@ public static void updateAction(Run<?, ?> build, List<String> resourceNames) {
// since the list *this.lockedResources* might be updated from multiple (parallel)
// stages, this operation need to be synchronized
private synchronized void add(ResourcePOJO r) {
for (ResourcePOJO pojo : this.lockedResources) {
if (pojo.getName().equals(r.getName())) {
pojo.inc();
return;
}
synchronized (this.syncResources) {
this.lockedResources.add(r);
}
this.lockedResources.add(r);
}

// -------------------------------------------------------------------------
Expand All @@ -110,7 +106,7 @@ public static LockedResourcesBuildAction fromResources(Collection<LockableResour
List<ResourcePOJO> resPojos = new ArrayList<>();
for (LockableResource r : resources) {
if (r != null) {
resPojos.add(new ResourcePOJO(r));
resPojos.add(new ResourcePOJO(r.getName(), "", ""));
}
}
return new LockedResourcesBuildAction(resPojos);
Expand All @@ -121,19 +117,16 @@ public static class ResourcePOJO {

// ---------------------------------------------------------------------
private String name;
private String description;
private int count = 1;
private String step;
private String action;
private long timeStamp;

// ---------------------------------------------------------------------
public ResourcePOJO(String name, String description) {
public ResourcePOJO(String name, String step, String action) {
this.name = name;
this.description = description;
}

// ---------------------------------------------------------------------
public ResourcePOJO(LockableResource r) {
this.name = r.getName();
this.description = r.getDescription();
this.step = step;
this.action = action;
this.timeStamp = new Date().getTime();
}

// ---------------------------------------------------------------------
Expand All @@ -142,23 +135,18 @@ public String getName() {
}

// ---------------------------------------------------------------------
public String getDescription() {
return this.description;
public String getStep() {
return this.step;
}

// ---------------------------------------------------------------------
/** Return the counter, how many was / is the resource used in the build.
* Example: you can use the lock() function in parallel stages for the
* same resource.
*/
public int getCounter() {
return this.count;
public String getAction() {
return this.action;
}

// ---------------------------------------------------------------------
/** Increment counter */
public void inc() {
this.count++;
public Date getTimeStamp() {
return new Date(this.timeStamp);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,26 +52,44 @@ THE SOFTWARE.

<div class="table-responsive">
<table
class="jenkins-table jenkins-!-margin-bottom-4 data-table"
class="jenkins-!-margin-bottom-4 table table-striped display data-table"
id="used-lockable-resources-by-build"
isLoaded="true"
data-remember-search-text="true"
data-columns-definition="[null, null, null, null]"
data-table-configuration="{}"
data-columns-definition="[null, null, null, null, null]"
data-table-configuration='
{
"stateSave": true,
"lengthMenu": [
[10, 25, 50, 100, -1],
[10, 25, 50, 100, "${%table.settings.page.length.all}"]
]
}'
>
<thead>
<th>${%table.column.index}</th>
<th>${%table.column.timeStamp}</th>
<th>${%table.column.action}</th>
<th>${%table.column.step}</th>
<th>${%table.column.name}</th>
<th>${%table.column.description}</th>
<th>${%table.column.counter}</th>
</thead>
<tbody>
<j:forEach var="resource" items="${it.lockedResources}" varStatus="idx">
<tr>
<td>${idx.index + 1}</td>
<td>
<j:if test="${resource.timeStamp.getTime() gt 0}">
<i:formatDate
value="${resource.timeStamp}"
type="both"
dateStyle="medium"
timeStyle="long"
/>
</j:if>
</td>
<td>${resource.action}</td>
<td>${resource.step}</td>
<td>${resource.name}</td>
<td>${resource.description}</td>
<td>${resource.counter}</td>
</tr>
</j:forEach>
</tbody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,7 @@ app.bar.resources=Lockable resources

table.column.index=Index
table.column.name=Resource Name
table.column.description=Description
table.column.counter=Counter
table.column.step=Step
table.column.timeStamp=Timestamp
table.column.action=Action
table.settings.page.length.all=ALL

0 comments on commit 8c01d45

Please sign in to comment.