Skip to content

Commit

Permalink
Add a way to list processes, and start to make UI
Browse files Browse the repository at this point in the history
  • Loading branch information
rowleya committed Jan 31, 2025
1 parent f6a47f9 commit c68ec79
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import static uk.ac.manchester.spinnaker.utils.CollectionUtils.copy;
import static uk.ac.manchester.spinnaker.utils.OptionalUtils.apply;

import java.io.IOException;
import java.net.InetAddress;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
Expand Down Expand Up @@ -83,11 +85,15 @@
import uk.ac.manchester.spinnaker.machine.ChipLocation;
import uk.ac.manchester.spinnaker.machine.HasChipLocation;
import uk.ac.manchester.spinnaker.machine.HasCoreLocation;
import uk.ac.manchester.spinnaker.machine.MachineVersion;
import uk.ac.manchester.spinnaker.machine.board.BMPCoords;
import uk.ac.manchester.spinnaker.machine.board.PhysicalCoords;
import uk.ac.manchester.spinnaker.machine.board.TriadCoords;
import uk.ac.manchester.spinnaker.spalloc.messages.BoardCoordinates;
import uk.ac.manchester.spinnaker.spalloc.messages.BoardPhysicalCoordinates;
import uk.ac.manchester.spinnaker.transceiver.SpinnmanException;
import uk.ac.manchester.spinnaker.transceiver.Transceiver;
import uk.ac.manchester.spinnaker.transceiver.TransceiverInterface;

/**
* The core implementation of the Spalloc service.
Expand Down Expand Up @@ -1704,6 +1710,8 @@ private final class SubMachineImpl implements SubMachine {

private List<Integer> boardIds;

private TransceiverInterface transceiver;

private SubMachineImpl(Connection conn) {
machine = getJobMachine(conn);
try (var getRootXY = conn.query(GET_ROOT_COORDS);
Expand Down Expand Up @@ -1813,6 +1821,17 @@ public void setPower(PowerState ps) {
}
powerController.setPower(id, ps, READY);
}

@Override
public TransceiverInterface getTransceiver() throws IOException,
InterruptedException, SpinnmanException {
if (transceiver == null) {
transceiver = new Transceiver(InetAddress.getByName(
connections.get(0).getHostname()),
MachineVersion.FIVE);
}
return transceiver;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static uk.ac.manchester.spinnaker.alloc.security.SecurityConfig.IS_NMPI_EXEC;
import static uk.ac.manchester.spinnaker.alloc.security.SecurityConfig.MAY_SEE_JOB_DETAILS;

import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
Expand Down Expand Up @@ -67,6 +68,8 @@
import uk.ac.manchester.spinnaker.machine.board.ValidTriadWidth;
import uk.ac.manchester.spinnaker.spalloc.messages.BoardCoordinates;
import uk.ac.manchester.spinnaker.spalloc.messages.BoardPhysicalCoordinates;
import uk.ac.manchester.spinnaker.transceiver.SpinnmanException;
import uk.ac.manchester.spinnaker.transceiver.TransceiverInterface;
import uk.ac.manchester.spinnaker.utils.UsedInJavadocOnly;
import uk.ac.manchester.spinnaker.utils.validation.IPAddress;

Expand Down Expand Up @@ -1227,5 +1230,18 @@ interface SubMachine {
* What to set the power state to.
*/
void setPower(@NotNull PowerState powerState);

/**
* Get a way to talk to the machine directly. Note that it might not be
* booted...
*
* @return The transceiver interface.
* @throws IOException if there is an issue creating the transceiver.
* @throws InterruptedException if the operation is interrupted.
* @throws SpinnmanException
* if there is an issue speaking to the machine.
*/
TransceiverInterface getTransceiver()
throws IOException, InterruptedException, SpinnmanException;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2025 The University of Manchester
*
* 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
*
* https://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 uk.ac.manchester.spinnaker.alloc.web;

import uk.ac.manchester.spinnaker.messages.model.CPUInfo;

/** A process in a list of processes. */
public class Process {

private CPUInfo info;

public Process(CPUInfo info) {
this.info = info;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public class RequestFailedException extends RuntimeException {
* @param cause
* The cause of the exception.
*/
private RequestFailedException(Status code, String message,
public RequestFailedException(Status code, String message,
Throwable cause) {
super(message, cause);
this.code = code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@ WhereIsResponse getJobChipLocation(
@Produces(APPLICATION_JSON)
void reportBoardIssue(IssueReportRequest report,
@Suspended AsyncResponse response);

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.ws.rs.QueryParam;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.web.authentication.logout.LogoutHandler;
Expand Down Expand Up @@ -198,4 +199,22 @@ ModelAndView powerJob(@PathVariable("id") int id,
@UsedInJavadocOnly(LogoutHandler.class)
String performLogout(HttpServletRequest request,
HttpServletResponse response);

/**
* Get the view for the job processes on a chip
*
* @param id
* Which job is being asked for
* @param x
* The x coordinate of the chip
* @param y
* The y coordinate of the chip
* @return View ({@code jobprocesses.jsp}) and model (based on
* {@link List<ProcessResponse>})
*/
@GetMapping("/job_processes/{id}")
@PreAuthorize(IS_READER)
@UsedInJavadocOnly(JobDescription.class)
ModelAndView listProcesses(@PathVariable("id") int id,
@QueryParam("x") int x, @QueryParam("y") int y);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static java.util.Objects.nonNull;
import static org.slf4j.LoggerFactory.getLogger;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.security.core.context.SecurityContextHolder.getContext;
import static org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder.on;
import static org.springframework.web.servlet.support.ServletUriComponentsBuilder.fromCurrentRequestUri;
Expand All @@ -42,6 +43,7 @@

import java.security.Principal;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
Expand Down Expand Up @@ -75,6 +77,7 @@
import uk.ac.manchester.spinnaker.alloc.security.AppAuthTransformationFilter;
import uk.ac.manchester.spinnaker.alloc.security.Permit;
import uk.ac.manchester.spinnaker.alloc.web.ControllerUtils.ViewFactory;
import uk.ac.manchester.spinnaker.machine.CoreSubsets;
import uk.ac.manchester.spinnaker.utils.UsedInJavadocOnly;

/**
Expand Down Expand Up @@ -104,6 +107,9 @@ public class SystemControllerImpl implements SystemController {

private static final ViewFactory JOB_VIEW = new ViewFactory("jobdetails");

private static final ViewFactory JOB_PROCESS_LIST_VIEW =
new ViewFactory("listjobprocesses");

// Must match what views expect
private static final String VERSION_OBJ = "version";

Expand All @@ -117,6 +123,8 @@ public class SystemControllerImpl implements SystemController {

private static final String ONE_MACHINE_OBJ = "machine";

private static final String JOB_PROCESSES_LIST_OBJ = "processList";

private static final String BASE_URI = "baseuri";

private static final long WAIT_FOR_POWER_SECONDS = 60;
Expand Down Expand Up @@ -372,6 +380,7 @@ public ModelAndView getJobInfo(int id) {
var mav = view(JOB_VIEW, ONE_JOB_OBJ, mach);
mav.addObject("deleteUri", uri(self().destroyJob(id, null)));
mav.addObject("powerUri", uri(self().powerJob(id, false)));
mav.addObject("processUri", uri(self().listProcesses(id, 0, 0)));
return mav;
}

Expand Down Expand Up @@ -409,4 +418,31 @@ public ModelAndView powerJob(int id, boolean power) {
mach.setMachineUrl(uri(self().getMachineInfo(mach.getMachine())));
return view(JOB_VIEW, ONE_JOB_OBJ, mach);
}

@Override
@PreAuthorize(IS_READER)
@Action("getting job process listing")
public ModelAndView listProcesses(int id, int x, int y) {
var permit = new Permit(getContext());
var job = spallocCore.getJob(permit, id)
.orElseThrow(() -> new ResponseStatusException(NOT_FOUND));
try {
var txrx = job.getMachine().get().getTransceiver();
CoreSubsets cores = new CoreSubsets();
for (int i = 0; i < 18; i++) {
cores.addCore(x, y, i);
}
var info = txrx.getCPUInformation(cores);
var response = new ArrayList<Process>();
for (var inf : info) {
response.add(new Process(inf));
}
return view(JOB_PROCESS_LIST_VIEW, JOB_PROCESSES_LIST_OBJ,
response);
} catch (Exception e) {
throw new ResponseStatusException(INTERNAL_SERVER_ERROR,
"Error receiving process details", e);
}
}

}
101 changes: 101 additions & 0 deletions SpiNNaker-allocserv/src/main/webapp/WEB-INF/views/listjobprocesses.jsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<html>
<%--
Copyright (c) 2025 The University of Manchester
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
https://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.
--%>
<jsp:include page="head.jsp">
<jsp:param name="title" value="Job Process List"/>
<jsp:param name="spalloclib" value="true" />
</jsp:include>
<body>

<h1>SpiNNaker Jobs</h1>

<c:choose>
<c:when test="${ not empty jobList }">
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>State</th>
<th>Power</th>
<th>Boards</th>
<th>Machine</th>
<th>Created at</th>
<th>Keepalive</th>
<th>Owner</th>
</tr>
</thead>
<tbody>
<c:forEach items="${ jobList }" var="job">
<tr>
<td class="textColumn">
<c:choose>
<c:when test="${ job.detailsUrl.present }">
<spring:eval var="jobDetailsUrl"
expression="job.detailsUrl.get()" />
<a href="${ jobDetailsUrl }"><code>${ job.id }</code></a>
</c:when>
<c:otherwise>
<code>${ job.id }</code>
</c:otherwise>
</c:choose>
</td>
<td class="textColumn">${ job.state }</td>
<td class="textColumn">${ job.powered ? "on" : "off" }</td>
<td class="numberColumn">
<spring:eval expression="job.numBoards.orElse(0)" />
</td>
<td class="textColumn">
<code><c:out value="${ job.machineName }" escapeXml="true" /></code>
</td>
<td class="textColumn">
<script defer="defer">
prettyTimestamp("start-${ job.id }");
</script>
<code id="start-${ job.id }">${ job.creationTimestamp }</code>
</td>
<td class="textColumn">
<script defer="defer">
prettyDuration("alive-${ job.id }");
</script>
<code id="alive-${ job.id }">${ job.keepaliveInterval }</code>
</td>
<td class="textColumn" id="owner-${ job.id }">
<c:if test="${ job.owner.present }">
<spring:eval htmlEscape="true"
expression="job.owner.get()" />
</c:if>
</td>
<td class="textColumn" hidden id="request-${ job.id }">
${ job.request }
</td>
<script defer="defer">
getJobOwner("request-${ job.id }", "owner-${ job.id }");
</script>
</tr>
</c:forEach>
</tbody>
</table>
</c:when>
<c:otherwise>
<p>No jobs are alive!</p>
</c:otherwise>
</c:choose>

<jsp:include page="basicfooter.jsp" />
</body>
</html>

0 comments on commit c68ec79

Please sign in to comment.