• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SpiNNakerManchester / JavaSpiNNaker / 13520271443

25 Feb 2025 11:34AM UTC coverage: 38.48% (-0.03%) from 38.51%
13520271443

push

github

rowleya
Fix tabs

675 of 2950 new or added lines in 17 files covered. (22.88%)

9 existing lines in 2 files now uncovered.

9182 of 23862 relevant lines covered (38.48%)

1.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.82
/SpiNNaker-allocserv/src/main/java/uk/ac/manchester/spinnaker/alloc/allocator/SpallocAPI.java
1
/*
2
 * Copyright (c) 2021 The University of Manchester
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package uk.ac.manchester.spinnaker.alloc.allocator;
17

18
import static java.util.Objects.isNull;
19
import static java.util.Objects.nonNull;
20
import static java.util.Objects.requireNonNull;
21
import static uk.ac.manchester.spinnaker.alloc.Constants.TRIAD_DEPTH;
22
import static uk.ac.manchester.spinnaker.alloc.security.SecurityConfig.IS_NMPI_EXEC;
23
import static uk.ac.manchester.spinnaker.alloc.security.SecurityConfig.MAY_SEE_JOB_DETAILS;
24

25
import java.io.IOException;
26
import java.time.Duration;
27
import java.time.Instant;
28
import java.util.Collection;
29
import java.util.List;
30
import java.util.Map;
31
import java.util.Objects;
32
import java.util.Optional;
33
import java.util.Set;
34

35
import javax.validation.Valid;
36
import javax.validation.constraints.AssertTrue;
37
import javax.validation.constraints.NotNull;
38
import javax.validation.constraints.Positive;
39
import javax.validation.constraints.PositiveOrZero;
40

41
import org.springframework.security.access.prepost.PostFilter;
42
import org.springframework.security.access.prepost.PreAuthorize;
43

44
import com.google.errorprone.annotations.Keep;
45

46
import uk.ac.manchester.spinnaker.alloc.compat.V1CompatService;
47
import uk.ac.manchester.spinnaker.alloc.model.BoardCoords;
48
import uk.ac.manchester.spinnaker.alloc.model.ConnectionInfo;
49
import uk.ac.manchester.spinnaker.alloc.model.DownLink;
50
import uk.ac.manchester.spinnaker.alloc.model.JobDescription;
51
import uk.ac.manchester.spinnaker.alloc.model.JobListEntryRecord;
52
import uk.ac.manchester.spinnaker.alloc.model.JobState;
53
import uk.ac.manchester.spinnaker.alloc.model.MachineDescription;
54
import uk.ac.manchester.spinnaker.alloc.model.MachineListEntryRecord;
55
import uk.ac.manchester.spinnaker.alloc.model.PowerState;
56
import uk.ac.manchester.spinnaker.alloc.proxy.ProxyCore;
57
import uk.ac.manchester.spinnaker.alloc.security.Permit;
58
import uk.ac.manchester.spinnaker.alloc.web.IssueReportRequest;
59
import uk.ac.manchester.spinnaker.machine.ChipLocation;
60
import uk.ac.manchester.spinnaker.machine.HasChipLocation;
61
import uk.ac.manchester.spinnaker.machine.HasCoreLocation;
62
import uk.ac.manchester.spinnaker.machine.ValidX;
63
import uk.ac.manchester.spinnaker.machine.ValidY;
64
import uk.ac.manchester.spinnaker.machine.board.BMPCoords;
65
import uk.ac.manchester.spinnaker.machine.board.PhysicalCoords;
66
import uk.ac.manchester.spinnaker.machine.board.TriadCoords;
67
import uk.ac.manchester.spinnaker.machine.board.ValidTriadHeight;
68
import uk.ac.manchester.spinnaker.machine.board.ValidTriadWidth;
69
import uk.ac.manchester.spinnaker.spalloc.messages.BoardCoordinates;
70
import uk.ac.manchester.spinnaker.spalloc.messages.BoardPhysicalCoordinates;
71
import uk.ac.manchester.spinnaker.transceiver.SpinnmanException;
72
import uk.ac.manchester.spinnaker.transceiver.TransceiverInterface;
73
import uk.ac.manchester.spinnaker.utils.UsedInJavadocOnly;
74
import uk.ac.manchester.spinnaker.utils.validation.IPAddress;
75

76
/**
77
 * The API of the core service that interacts with the database.
78
 *
79
 * @author Donal Fellows
80
 */
81
public interface SpallocAPI {
82
        /**
83
         * List the machines.
84
         *
85
         * @param allowOutOfService
86
         *            Whether to include machines marked as out of service.
87
         * @return A mapping from names to machines (which are live objects).
88
         */
89
        Map<String, Machine> getMachines(boolean allowOutOfService);
90

91
        /**
92
         * List the machines.
93
         *
94
         * @param allowOutOfService
95
         *            Whether to include machines marked as out of service.
96
         * @return A description of all the machines.
97
         */
98
        List<MachineListEntryRecord> listMachines(boolean allowOutOfService);
99

100
        /**
101
         * Get a specific machine.
102
         *
103
         * @param name
104
         *            The name of the machine to get.
105
         * @param allowOutOfService
106
         *            Whether to include machines marked as out of service.
107
         * @return A machine, on which more operations can be done.
108
         */
109
        Optional<Machine> getMachine(@NotNull String name,
110
                        boolean allowOutOfService);
111

112
        /**
113
         * Get info about a specific machine.
114
         *
115
         * @param machine
116
         *            The name of the machine to get.
117
         * @param allowOutOfService
118
         *            Whether to include machines marked as out of service.
119
         * @param permit
120
         *            Encodes what the caller may do.
121
         * @return A machine description model.
122
         */
123
        Optional<MachineDescription> getMachineInfo(@NotNull String machine,
124
                        boolean allowOutOfService, Permit permit);
125

126
        /**
127
         * List the jobs.
128
         *
129
         * @param deleted
130
         *            Whether to include deleted jobs in the list.
131
         * @param limit
132
         *            Maximum number of jobs in the returned list. Used for paging.
133
         * @param start
134
         *            How many jobs to skip past. Used for paging.
135
         * @return A list of jobs.
136
         */
137
        Jobs getJobs(boolean deleted, int limit, int start);
138

139
        /**
140
         * List the active jobs.
141
         *
142
         * @param permit
143
         *            Encodes what the caller may do.
144
         * @return A description of all the active jobs.
145
         */
146
        List<JobListEntryRecord> listJobs(Permit permit);
147

148
        /**
149
         * Get a specific job. Only owners or admins can see full job details or
150
         * manipulate the job.
151
         *
152
         * @param permit
153
         *            Encodes what the caller may do.
154
         * @param id
155
         *            The identifier of the job.
156
         * @return A job object on which more operations can be done, or empty if
157
         *         the job isn't there or isn't available to you.
158
         */
159
        @PostFilter(MAY_SEE_JOB_DETAILS)
160
        Optional<Job> getJob(Permit permit, int id);
161

162
        /**
163
         * Get a specific job. Only owners or admins can see full job details or
164
         * manipulate the job.
165
         *
166
         * @param permit
167
         *            Encodes what the caller may do.
168
         * @param id
169
         *            The identifier of the job.
170
         * @return A job description, or empty if the job isn't there (or isn't
171
         *         available to you).
172
         */
173
        @PostFilter(MAY_SEE_JOB_DETAILS)
174
        Optional<JobDescription> getJobInfo(Permit permit, int id);
175

176
        /**
177
         * Create a job for a user that is only in one group.
178
         * Note that jobs <em>cannot</em> be created on machines that
179
         * are out of service, but marking a machine as out of service does not stop
180
         * the jobs that are already running on it.
181
         *
182
         * @param owner
183
         *            Who is making this job.
184
         * @param descriptor
185
         *            What sort of allocation is desired?
186
         * @param machineName
187
         *            The name of the machine the user wants to allocate on, or
188
         *            {@code null} if they want to select by tags.
189
         * @param tags
190
         *            The tags of the machine the user wants to allocate on, or
191
         *            {@code null} if they want to select by name.
192
         * @param keepaliveInterval
193
         *            The maximum interval between keepalive requests or the job
194
         *            becomes eligible for automated deletion.
195
         * @param originalRequest
196
         *            The serialized original request, which will be stored in the
197
         *            database for later retrieval.
198
         * @return The job created.
199
         * @throws IllegalArgumentException if the job could not be created.
200
         */
201
        Job createJob(@NotNull String owner,
202
                        @Valid CreateDescriptor descriptor, String machineName,
203
                        List<String> tags, Duration keepaliveInterval,
204
                        byte[] originalRequest) throws IllegalArgumentException;
205

206
        /**
207
         * Create a job for a user in a specific local group.
208
         * Note that jobs <em>cannot</em> be created on machines that
209
         * are out of service, but marking a machine as out of service does not stop
210
         * the jobs that are already running on it.
211
         *
212
         * @param owner
213
         *            Who is making this job.
214
         * @param group
215
         *            What group is associated with this job for accounting
216
         *            purposes.
217
         * @param descriptor
218
         *            What sort of allocation is desired?
219
         * @param machineName
220
         *            The name of the machine the user wants to allocate on, or
221
         *            {@code null} if they want to select by tags.
222
         * @param tags
223
         *            The tags of the machine the user wants to allocate on, or
224
         *            {@code null} if they want to select by name.
225
         * @param keepaliveInterval
226
         *            The maximum interval between keepalive requests or the job
227
         *            becomes eligible for automated deletion.
228
         * @param originalRequest
229
         *            The serialized original request, which will be stored in the
230
         *            database for later retrieval.
231
         * @return The job created.
232
         * @throws IllegalArgumentException if the job could not be created.
233
         */
234
        Job createJobInGroup(@NotNull String owner, @NotNull String group,
235
                        @Valid CreateDescriptor descriptor, String machineName,
236
                        List<String> tags, Duration keepaliveInterval,
237
                        byte[] originalRequest) throws IllegalArgumentException;
238

239
        /**
240
         * Create a job for interactive use in an NMPI Collab Session.
241
         * Note that jobs <em>cannot</em> be created on machines that
242
         * are out of service, but marking a machine as out of service does not stop
243
         * the jobs that are already running on it.
244
         *
245
         * @param owner
246
         *            Who is making this job.
247
         * @param nmpiCollab
248
         *            The NMPI Collab to manage a session in, and from which the
249
         *            quota will be used.
250
         * @param descriptor
251
         *            What sort of allocation is desired?
252
         * @param machineName
253
         *            The name of the machine the user wants to allocate on, or
254
         *            {@code null} if they want to select by tags.
255
         * @param tags
256
         *            The tags of the machine the user wants to allocate on, or
257
         *            {@code null} if they want to select by name.
258
         * @param keepaliveInterval
259
         *            The maximum interval between keepalive requests or the job
260
         *            becomes eligible for automated deletion.
261
         * @param originalRequest
262
         *            The serialized original request, which will be stored in the
263
         *            database for later retrieval.
264
         * @return The job created.
265
         * @throws IllegalArgumentException if the job could not be created.
266
         */
267
        Job createJobInCollabSession(@NotNull String owner,
268
                        @NotNull String nmpiCollab,
269
                        @Valid CreateDescriptor descriptor, String machineName,
270
                        List<String> tags, Duration keepaliveInterval,
271
                        byte[] originalRequest) throws IllegalArgumentException;
272

273
        /**
274
         * Create a job for interactive use in an NMPI Collab Session.
275
         * Note that jobs <em>cannot</em> be created on machines that
276
         * are out of service, but marking a machine as out of service does not stop
277
         * the jobs that are already running on it.
278
         *
279
         * @param owner
280
         *            Who is making this job.
281
         * @param nmpiJobId
282
         *            The NMPI Job to allocate the quota used to.  The collab of
283
         *            the Job will be used for internal accounting purposes.
284
         * @param descriptor
285
         *            What sort of allocation is desired?
286
         * @param machineName
287
         *            The name of the machine the user wants to allocate on, or
288
         *            {@code null} if they want to select by tags.
289
         * @param tags
290
         *            The tags of the machine the user wants to allocate on, or
291
         *            {@code null} if they want to select by name.
292
         * @param keepaliveInterval
293
         *            The maximum interval between keepalive requests or the job
294
         *            becomes eligible for automated deletion.
295
         * @param originalRequest
296
         *            The serialized original request, which will be stored in the
297
         *            database for later retrieval.
298
         * @return The job created.
299
         * @throws IllegalArgumentException if the job could not be created.
300
         */
301
        @PreAuthorize(IS_NMPI_EXEC)
302
        Job createJobForNMPIJob(@NotNull String owner, int nmpiJobId,
303
                        @Valid CreateDescriptor descriptor,        String machineName,
304
                        List<String> tags, Duration keepaliveInterval,
305
                        byte[] originalRequest) throws IllegalArgumentException;
306

307
        /** Purge the cache of what boards are down. */
308
        void purgeDownCache();
309

310
        /**
311
         * Tells the service that there may be a problem with a board at a
312
         * particular address.
313
         *
314
         * @param address
315
         *            The IP address of the board. Note that we haven't yet
316
         *            identified which machine has the board.
317
         * @param coreLocation
318
         *            Where on the board is the problem. If the problem is at the
319
         *            core level, it's a {@link HasCoreLocation}. If the problem is
320
         *            at the board level, this is {@code null}.
321
         * @param description
322
         *            Optional problem description. May be {@code null}.
323
         * @param permit
324
         *            Who is making the request.
325
         */
326
        @UsedInJavadocOnly(HasCoreLocation.class)
327
        void reportProblem(@IPAddress String address, HasChipLocation coreLocation,
328
                        String description, Permit permit);
329

330
        /**
331
         * Describes what sort of request to create a job this is.
332
         *
333
         * @see CreateNumBoards
334
         * @see CreateDimensions
335
         * @see CreateDimensionsAt
336
         * @see CreateBoard
337
         */
338
        abstract class CreateDescriptor {
339
                /**
340
                 * The maximum number of dead boards tolerated in the allocation.
341
                 * Ignored when asking for a single board.
342
                 */
343
                @PositiveOrZero(message = "maxDeadBoards must not be negative")
344
                public final int maxDead;
345

346
                /**
347
                 * Only known subclasses permitted.
348
                 *
349
                 * @param maxDeadBoards
350
                 *            The maximum number of dead boards. {@code null} is
351
                 *            equivalent to 0.
352
                 */
353
                private CreateDescriptor(Integer maxDeadBoards) {
3✔
354
                        this.maxDead = isNull(maxDeadBoards) ? 0 : maxDeadBoards;
3✔
355
                }
3✔
356

357
                /**
358
                 * Apply a visitor to this descriptor.
359
                 *
360
                 * @param <T>
361
                 *            The type of the result of the visiting.
362
                 * @param visitor
363
                 *            The visitor to apply.
364
                 * @return The result computed by the visitor.
365
                 */
366
                public final <T> T visit(CreateVisitor<T> visitor) {
367
                        return doVisit(requireNonNull(visitor));
3✔
368
                }
369

370
                /**
371
                 * Get the area. The area is the number of boards required.
372
                 *
373
                 * @return The number of boards requested by the job.
374
                 */
375
                public abstract int getArea();
376

377
                abstract <T> T doVisit(CreateVisitor<T> visitor);
378
        }
379

380
        /**
381
         * A request for a number of boards.
382
         */
383
        final class CreateNumBoards extends CreateDescriptor {
384
                /** The number of boards requested. */
385
                @Positive(message = "number of boards to request must be positive")
386
                public final int numBoards;
387

388
                /**
389
                 * Request a count of boards. The service <em>may</em> over-allocate.
390
                 *
391
                 * @param numBoards
392
                 *            The number of boards desired.
393
                 * @param maxDeadBoards
394
                 *            The number of dead boards that can be tolerated within
395
                 *            that.
396
                 */
397
                public CreateNumBoards(int numBoards, Integer maxDeadBoards) {
398
                        super(maxDeadBoards);
3✔
399
                        this.numBoards = numBoards;
3✔
400
                }
3✔
401

402
                @Override
403
                <T> T doVisit(CreateVisitor<T> visitor) {
404
                        return visitor.numBoards(this);
3✔
405
                }
406

407
                @Override
408
                public int getArea() {
409
                        return numBoards;
3✔
410
                }
411
        }
412

413
        /**
414
         * A request for a rectangle of boards. This is expressed in boards for
415
         * reasons relating to the legacy API.
416
         *
417
         * @see V1CompatService
418
         */
419
        @UsedInJavadocOnly(V1CompatService.class)
420
        final class CreateDimensions extends CreateDescriptor {
421
                /** Width requested, in triads. */
422
                @ValidTriadWidth
423
                public final int width;
424

425
                /** Height requested, in triads. */
426
                @ValidTriadHeight
427
                public final int height;
428

429
                /**
430
                 * Request a rectangle of boards. The service <em>may</em>
431
                 * over-allocate.
432
                 *
433
                 * @param width
434
                 *            The width of rectangle to request, in triads.
435
                 * @param height
436
                 *            The height of rectangle to request, in triads.
437
                 * @param maxDeadBoards
438
                 *            The number of dead boards that can be tolerated in that
439
                 *            rectangle.
440
                 */
441
                public CreateDimensions(int width, int height, Integer maxDeadBoards) {
442
                        super(maxDeadBoards);
3✔
443
                        this.width = width;
3✔
444
                        this.height = height;
3✔
445
                }
3✔
446

447
                @Override
448
                <T> T doVisit(CreateVisitor<T> visitor) {
449
                        return visitor.dimensions(this);
3✔
450
                }
451

452
                @Override
453
                public int getArea() {
454
                        return width * height;
3✔
455
                }
456
        }
457

458
        /** Some requests have the locations of boards. */
459
        abstract class HasBoardCoords extends CreateDescriptor {
460
                /** The logical coordinates, or {@code null}. */
461
                @Valid
462
                public final TriadCoords triad;
463

464
                /** The physical coordinates, or {@code null}. */
465
                @Valid
466
                public final PhysicalCoords physical;
467

468
                /** The network coordinates, or {@code null}. */
469
                @IPAddress(nullOK = true)
470
                public final String ip;
471

472
                private HasBoardCoords(TriadCoords triad, PhysicalCoords physical,
473
                                String ip, Integer maxDeadBoards) {
474
                        super(maxDeadBoards);
3✔
475
                        this.triad = triad;
3✔
476
                        this.physical = physical;
3✔
477
                        this.ip = ip;
3✔
478
                }
3✔
479

480
                private static int get(Integer value) {
NEW
481
                        return Objects.nonNull(value) ? value : 0;
×
482
                }
483

484
                @Keep
485
                @AssertTrue(message = "a method of locating a board must be provided")
486
                private boolean isLocated() {
NEW
487
                        return nonNull(triad) || nonNull(physical) || nonNull(ip);
×
488
                }
489
        }
490

491
        /**
492
         * A request for a rectangle of triads rooted at a particular triad. No
493
         * option for using physical coordinates is supported with this method.
494
         */
495
        final class CreateDimensionsAt extends HasBoardCoords {
496
                /** Width requested, in triads. */
497
                @ValidTriadWidth
498
                public final int width;
499

500
                /** Height requested, in triads. */
501
                @ValidTriadHeight
502
                public final int height;
503

504
                /**
505
                 * Create a request for a rectangle at a specific board. The board will
506
                 * have a Z coordinate of 0.
507
                 *
508
                 * @param width
509
                 *            Width requested, in triads.
510
                 * @param height
511
                 *            Height requested, in triads.
512
                 * @param x
513
                 *            The X coordinate of the root board of the request.
514
                 * @param y
515
                 *            The Y coordinate of the root board of the request.
516
                 * @param maxDeadBoards
517
                 *            The maximum number of dead boards tolerated in the
518
                 *            allocation. Ignored when asking for a single board.
519
                 */
520
                public CreateDimensionsAt(int width, int height, int x, int y,
521
                                Integer maxDeadBoards) {
NEW
522
                        super(new TriadCoords(x, y, 0), null, null, maxDeadBoards);
×
NEW
523
                        this.width = width;
×
NEW
524
                        this.height = height;
×
NEW
525
                }
×
526

527
                /**
528
                 * Create a request for a rectangle at a specific board. The board will
529
                 * have a Z coordinate of 0.
530
                 *
531
                 * @param width
532
                 *            Width requested, in triads.
533
                 * @param height
534
                 *            Height requested, in triads.
535
                 * @param x
536
                 *            The X coordinate of the root board of the request.
537
                 * @param y
538
                 *            The Y coordinate of the root board of the request.
539
                 * @param maxDeadBoards
540
                 *            The maximum number of dead boards tolerated in the
541
                 *            allocation. Ignored when asking for a single board.
542
                 */
543
                public CreateDimensionsAt(int width, int height, Integer x, Integer y,
544
                                Integer maxDeadBoards) {
NEW
545
                        super(new TriadCoords(HasBoardCoords.get(x), HasBoardCoords.get(y),
×
546
                                        0), null, null, maxDeadBoards);
NEW
547
                        this.width = width;
×
NEW
548
                        this.height = height;
×
NEW
549
                }
×
550

551
                /**
552
                 * Create a request for a rectangle at a specific board. The board must
553
                 * have a Z coordinate of 0.
554
                 *
555
                 * @param width
556
                 *            Width requested, in triads.
557
                 * @param height
558
                 *            Height requested, in triads.
559
                 * @param x
560
                 *            The X coordinate of the root board of the request.
561
                 * @param y
562
                 *            The Y coordinate of the root board of the request.
563
                 * @param z
564
                 *            The Z coordinate of the root board of the request.
565
                 * @param maxDeadBoards
566
                 *            The maximum number of dead boards tolerated in the
567
                 *            allocation. Ignored when asking for a single board.
568
                 */
569
                public CreateDimensionsAt(int width, int height, int x, int y, int z,
570
                                Integer maxDeadBoards) {
NEW
571
                        super(new TriadCoords(x, y, z), null, null, maxDeadBoards);
×
NEW
572
                        this.width = width;
×
NEW
573
                        this.height = height;
×
NEW
574
                }
×
575

576
                /**
577
                 * Create a request for a rectangle at a specific board. The board must
578
                 * have a Z coordinate of 0.
579
                 *
580
                 * @param width
581
                 *            Width requested, in triads.
582
                 * @param height
583
                 *            Height requested, in triads.
584
                 * @param x
585
                 *            The X coordinate of the root board of the request.
586
                 * @param y
587
                 *            The Y coordinate of the root board of the request.
588
                 * @param z
589
                 *            The Z coordinate of the root board of the request.
590
                 * @param maxDeadBoards
591
                 *            The maximum number of dead boards tolerated in the
592
                 *            allocation. Ignored when asking for a single board.
593
                 */
594
                public CreateDimensionsAt(int width, int height, Integer x, Integer y,
595
                                Integer z, Integer maxDeadBoards) {
NEW
596
                        super(new TriadCoords(HasBoardCoords.get(x), HasBoardCoords.get(y),
×
NEW
597
                                        HasBoardCoords.get(z)), null, null, maxDeadBoards);
×
NEW
598
                        this.width = width;
×
NEW
599
                        this.height = height;
×
NEW
600
                }
×
601

602
                /**
603
                 * Create a request for a rectangle at a specific board. The board must
604
                 * have a Z coordinate of 0.
605
                 *
606
                 * @param width
607
                 *            Width requested, in triads.
608
                 * @param height
609
                 *            Height requested, in triads.
610
                 * @param ip
611
                 *            The network address of the root board of the request.
612
                 * @param maxDeadBoards
613
                 *            The maximum number of dead boards tolerated in the
614
                 *            allocation. Ignored when asking for a single board.
615
                 */
616
                public CreateDimensionsAt(int width, int height, String ip,
617
                                Integer maxDeadBoards) {
618
                        super(null, null, ip, maxDeadBoards);
3✔
619
                        this.width = width;
3✔
620
                        this.height = height;
3✔
621
                }
3✔
622

623
                private CreateDimensionsAt(int width, int height,
624
                                PhysicalCoords physical, Integer maxDeadBoards) {
NEW
625
                        super(null, physical, null, maxDeadBoards);
×
NEW
626
                        this.width = width;
×
NEW
627
                        this.height = height;
×
NEW
628
                }
×
629

630
                /**
631
                 * Create a request for a rectangle at a specific board. The board must
632
                 * have a Z coordinate of 0.
633
                 *
634
                 * @param width
635
                 *            Width requested, in triads.
636
                 * @param height
637
                 *            Height requested, in triads.
638
                 * @param cabinet
639
                 *            The cabinet number of the root board of the request.
640
                 * @param frame
641
                 *            The frame number of the root board.
642
                 * @param board
643
                 *            The board number of the root board.
644
                 * @param maxDeadBoards
645
                 *            The maximum number of dead boards tolerated in the
646
                 *            allocation. Ignored when asking for a single board.
647
                 * @return Descriptor
648
                 */
649
                public static CreateDimensionsAt physical(int width, int height,
650
                                int cabinet, int frame, int board, Integer maxDeadBoards) {
651
                        // Done like this to avoid syntactic ambiguity
NEW
652
                        return new CreateDimensionsAt(width, height,
×
653
                                        new PhysicalCoords(cabinet, frame, board), maxDeadBoards);
654
                }
655

656
                /**
657
                 * Create a request for a rectangle at a specific board. The board must
658
                 * have a Z coordinate of 0.
659
                 *
660
                 * @param width
661
                 *            Width requested, in triads.
662
                 * @param height
663
                 *            Height requested, in triads.
664
                 * @param cabinet
665
                 *            The cabinet number of the root board of the request.
666
                 * @param frame
667
                 *            The frame number of the root board.
668
                 * @param board
669
                 *            The board number of the root board.
670
                 * @param maxDeadBoards
671
                 *            The maximum number of dead boards tolerated in the
672
                 *            allocation. Ignored when asking for a single board.
673
                 * @return Descriptor
674
                 */
675
                public static CreateDimensionsAt physical(int width, int height,
676
                                Integer cabinet, Integer frame, Integer board,
677
                                Integer maxDeadBoards) {
678
                        // Done like this to avoid syntactic ambiguity
NEW
679
                        return new CreateDimensionsAt(width, height,
×
NEW
680
                                        new PhysicalCoords(HasBoardCoords.get(cabinet),
×
NEW
681
                                                        HasBoardCoords.get(frame),
×
NEW
682
                                                        HasBoardCoords.get(board)),
×
683
                                        maxDeadBoards);
684
                }
685

686
                @Override
687
                <T> T doVisit(CreateVisitor<T> visitor) {
688
                        return visitor.dimensionsAt(this);
3✔
689
                }
690

691
                @Override
692
                public int getArea() {
693
                        return width * height * TRIAD_DEPTH;
3✔
694
                }
695
        }
696

697
        /**
698
         * A request for a specific board.
699
         */
700
        final class CreateBoard extends HasBoardCoords {
701
                private CreateBoard(TriadCoords triad, PhysicalCoords physical,
702
                                String ip) {
703
                        super(triad, physical, ip, null);
3✔
704
                }
3✔
705

706
                /**
707
                 * Create a request for a specific board.
708
                 *
709
                 * @param x
710
                 *            The X coordinate of the board.
711
                 * @param y
712
                 *            The Y coordinate of the board.
713
                 * @param z
714
                 *            The Z coordinate of the board.
715
                 * @return Descriptor
716
                 */
717
                public static CreateBoard triad(int x, int y, int z) {
718
                        return new CreateBoard(new TriadCoords(x, y, z), null, null);
3✔
719
                }
720

721
                /**
722
                 * Create a request for a specific board.
723
                 *
724
                 * @param cabinet
725
                 *            The cabinet number of the board.
726
                 * @param frame
727
                 *            The frame number of the board.
728
                 * @param board
729
                 *            The board number of the board.
730
                 * @return Descriptor
731
                 */
732
                public static CreateBoard physical(int cabinet, int frame, int board) {
NEW
733
                        return new CreateBoard(null,
×
734
                                        new PhysicalCoords(cabinet, frame, board), null);
735
                }
736

737
                /**
738
                 * Create a request for a specific board.
739
                 *
740
                 * @param ip
741
                 *            The network address of the board.
742
                 * @return Descriptor
743
                 */
744
                public static CreateBoard address(@IPAddress String ip) {
NEW
745
                        return new CreateBoard(null, null, ip);
×
746
                }
747

748
                @Override
749
                <T> T doVisit(CreateVisitor<T> visitor) {
750
                        return visitor.board(this);
3✔
751
                }
752

753
                @Override
754
                public int getArea() {
755
                        return 1;
3✔
756
                }
757
        }
758

759
        /**
760
         * Visitor for {@link CreateDescriptor}.
761
         *
762
         * @param <T>
763
         *            The type of the result of visiting.
764
         */
765
        interface CreateVisitor<T> {
766
                /**
767
                 * Visit a descriptor.
768
                 *
769
                 * @param createNumBoards
770
                 *            The descriptor.
771
                 * @return The result of the visiting.
772
                 */
773
                T numBoards(@NotNull CreateNumBoards createNumBoards);
774

775
                /**
776
                 * Visit a descriptor.
777
                 *
778
                 * @param createDimensionsAt
779
                 *            The descriptor.
780
                 * @return The result of the visiting.
781
                 */
782
                T dimensionsAt(@NotNull CreateDimensionsAt createDimensionsAt);
783

784
                /**
785
                 * Visit a descriptor.
786
                 *
787
                 * @param createDimensions
788
                 *            The descriptor.
789
                 * @return The result of the visiting.
790
                 */
791
                T dimensions(@NotNull CreateDimensions createDimensions);
792

793
                /**
794
                 * Visit a descriptor.
795
                 *
796
                 * @param createBoard
797
                 *            The descriptor.
798
                 * @return The result of the visiting.
799
                 */
800
                T board(@NotNull CreateBoard createBoard);
801
        }
802

803
        /**
804
         * A thing that may be waited upon.
805
         *
806
         * @author Donal Fellows
807
         */
808
        interface Waitable {
809
                /**
810
                 * Wait for the object to (maybe) change, or for the timeout to expire.
811
                 * This is a best-effort method.
812
                 * <p>
813
                 * This method does <em>not</em> throw {@link InterruptedException}; on
814
                 * interruption, it simply returns early (but the
815
                 * {@linkplain Thread#interrupted() interrupted status} of the thread is
816
                 * set).
817
                 *
818
                 * @param timeout
819
                 *            How long to wait.
820
                 * @return True if the wait was interrupted,
821
                 *         False if the timeout expired
822
                 */
823
                boolean waitForChange(@NotNull Duration timeout);
824
        }
825

826
        /**
827
         * Describes a particular job known to the allocator.
828
         *
829
         * @author Donal Fellows
830
         */
831
        interface Job extends Waitable {
832
                /** @return Job ID */
833
                int getId();
834

835
                /**
836
                 * Update the keepalive.
837
                 *
838
                 * @param keepaliveAddress
839
                 *            Where was the access from.
840
                 */
841
                void access(@NotNull @IPAddress String keepaliveAddress);
842

843
                /**
844
                 * Mark the job as destroyed. To do this to an already destroyed job is
845
                 * a no-op.
846
                 *
847
                 * @param reason
848
                 *            Why the job is being destroyed.
849
                 */
850
                void destroy(String reason);
851

852
                /**
853
                 * Power a job on or off.
854
                 *
855
                 * @param power True for on, False for off
856
                 */
857
                void setPower(boolean power);
858

859
                /**
860
                 * @return The state of the job.
861
                 */
862
                JobState getState();
863

864
                /**
865
                 * @return When the job started.
866
                 */
867
                Instant getStartTime();
868

869
                /**
870
                 * @return Host address that issued last keepalive event, or
871
                 *         {@link Optional#empty() empty()} if this information is not
872
                 *         available to the current user.
873
                 */
874
                Optional<String> getKeepaliveHost();
875

876
                /**
877
                 * @return Time of the last keepalive event.
878
                 */
879
                Instant getKeepaliveTimestamp();
880

881
                /**
882
                 * @return The creator of the job. {@link Optional#empty() empty()} if
883
                 *         this is not available to the current user.
884
                 */
885
                Optional<String> getOwner();
886

887
                /**
888
                 * @return The serialized original request to create the job.
889
                 *         {@link Optional#empty() empty()} if this is not available to
890
                 *         the current user.
891
                 */
892
                Optional<byte[]> getOriginalRequest();
893

894
                /**
895
                 * @return When the job finished. {@link Optional#empty() empty()} if
896
                 *         the job is not yet finished.
897
                 */
898
                Optional<Instant> getFinishTime();
899

900
                /**
901
                 * @return Why the job died. Might be {@link Optional#empty() empty()}
902
                 *         if this isn't known (including if the job is alive).
903
                 */
904
                Optional<String> getReason();
905

906
                /**
907
                 * @return The (sub-)machine allocated to the job.
908
                 *         {@link Optional#empty() empty()} if no resources allocated.
909
                 */
910
                Optional<SubMachine> getMachine();
911

912
                /**
913
                 * Locate a board within the allocation.
914
                 *
915
                 * @param x
916
                 *            The X coordinate of a chip on the board of interest.
917
                 * @param y
918
                 *            The Y coordinate of a chip on the board of interest.
919
                 * @return The location, if resources allocated and the location maps.
920
                 *         {@link Optional#empty() empty()} otherwise.
921
                 */
922
                Optional<BoardLocation> whereIs(@ValidX int x, @ValidY int y);
923

924
                /**
925
                 * @return The absolute location of root chip. {@link Optional#empty()
926
                 *         empty()} if no resources allocated.
927
                 */
928
                Optional<ChipLocation> getRootChip();
929

930
                /**
931
                 * @return the allocated width of the job's rectangle of triads, or
932
                 *         {@link Optional#empty() empty()} if not allocated (or not
933
                 *         known).
934
                 */
935
                Optional<Integer> getWidth();
936

937
                /**
938
                 * @return the allocated height of the job's rectangle of triads, or
939
                 *         {@link Optional#empty() empty()} if not allocated (or not
940
                 *         known).
941
                 */
942
                Optional<Integer> getHeight();
943

944
                /**
945
                 * @return the allocated depth of this sub-machine, or
946
                 *         {@link Optional#empty() empty()} if not allocated (or not
947
                 *         known). When supplied, will be 1 (single board) or 3 (by
948
                 *         triad)
949
                 */
950
                Optional<Integer> getDepth();
951

952
                /**
953
                 * Report an issue with some boards in the job.
954
                 *
955
                 * @param reqBody
956
                 *            The description of the issue.
957
                 * @param permit
958
                 *            Who is actually reporting this?
959
                 * @return The text part of the response
960
                 */
961
                String reportIssue(IssueReportRequest reqBody, Permit permit);
962

963
                /**
964
                 * Note that a proxy has been set up for the job. This allows the proxy
965
                 * to be closed when the job state changes. (The proxy may already be
966
                 * closed at that point.)
967
                 *
968
                 * @param proxy
969
                 *            The proxy.
970
                 */
971
                void rememberProxy(ProxyCore proxy);
972

973
                /**
974
                 * Note that a proxy has been dropped from the job and doesn't need to
975
                 * be remembered any more.
976
                 *
977
                 * @param proxy
978
                 *            The proxy.
979
                 */
980
                void forgetProxy(ProxyCore proxy);
981

982
                /**
983
                 * Get a way to talk to the machine directly.  Note that it might not be
984
                 * booted...
985
                 *
986
                 * @return The transceiver interface.
987
                 * @throws IOException if there is an issue creating the transceiver.
988
                 * @throws InterruptedException if the operation is interrupted.
989
                 * @throws SpinnmanException
990
                 *         if there is an issue speaking to the machine.
991
                 */
992
                TransceiverInterface getTransceiver()
993
                                throws IOException, InterruptedException, SpinnmanException;
994
        }
995

996
        /**
997
         * Describes a list of jobs known to the allocator.
998
         *
999
         * @author Donal Fellows
1000
         */
1001
        interface Jobs extends Waitable {
1002
                /**
1003
                 * @return The job IDs.
1004
                 */
1005
                List<Integer> ids();
1006

1007
                /**
1008
                 * @return The jobs. Simplified view only. (No keepalive host or owner
1009
                 *         information.)
1010
                 */
1011
                List<Job> jobs();
1012

1013
                /**
1014
                 * @param duration
1015
                 *            How long to wait for a change.
1016
                 * @return The set of jobs that have changed.
1017
                 */
1018
                Collection<Integer> getChanged(Duration duration);
1019
        }
1020

1021
        /**
1022
         * Describes a particular machine known to the allocator. Must implement
1023
         * equality by ID or name (both are unique).
1024
         *
1025
         * @author Donal Fellows
1026
         */
1027
        interface Machine extends Waitable {
1028
                /** @return The ID of the machine. Unique. */
1029
                int getId();
1030

1031
                /** @return The name of the machine. Unique. */
1032
                String getName();
1033

1034
                /** @return The tags associated with the machine. */
1035
                Set<String> getTags();
1036

1037
                /** @return The width of the machine. */
1038
                int getWidth();
1039

1040
                /** @return The height of the machine. */
1041
                int getHeight();
1042

1043
                /** @return Whether the machine wraps in the horizontal direction. */
1044
                boolean isHorizonallyWrapped();
1045

1046
                /** @return Whether the machine wraps in the vertical direction. */
1047
                boolean isVerticallyWrapped();
1048

1049
                /** @return Whether this machine is currently in service. */
1050
                boolean isInService();
1051

1052
                /**
1053
                 * The IDs of boards marked as dead or otherwise taken out of service.
1054
                 *
1055
                 * @return A list of boards. Not modifiable.
1056
                 */
1057
                List<BoardCoords> getDeadBoards();
1058

1059
                /**
1060
                 * The links within the machine that are marked as dead or otherwise
1061
                 * taken out of service. Note that this does not include links that lead
1062
                 * out of the machine.
1063
                 *
1064
                 * @return A list of links. Not modifiable.
1065
                 */
1066
                List<DownLink> getDownLinks();
1067

1068
                /**
1069
                 * Get a description of the location of a board given the global
1070
                 * coordinates of a chip on it.
1071
                 *
1072
                 * @param chipLocation
1073
                 *            Global chip coordinates.
1074
                 * @return Board location description
1075
                 */
1076
                Optional<BoardLocation> getBoardByChip(
1077
                                @Valid @NotNull HasChipLocation chipLocation);
1078

1079
                /**
1080
                 * Get a description of the location of a board given the physical
1081
                 * coordinates of the board.
1082
                 *
1083
                 * @param coords
1084
                 *            PhysicalCoordinates
1085
                 * @return Board location description
1086
                 */
1087
                Optional<BoardLocation> getBoardByPhysicalCoords(
1088
                                @Valid @NotNull PhysicalCoords coords);
1089

1090
                /**
1091
                 * Get a description of the location of a board given the triad
1092
                 * coordinates of the board.
1093
                 *
1094
                 * @param coords
1095
                 *            Triad coordinates.
1096
                 * @return Board location description
1097
                 */
1098
                Optional<BoardLocation> getBoardByLogicalCoords(
1099
                                @Valid @NotNull TriadCoords coords);
1100

1101
                /**
1102
                 * Get a description of the location of a board given the address of its
1103
                 * ethernet chip.
1104
                 *
1105
                 * @param address
1106
                 *            IP address of the board (in {@code 0.0.0.0} form; will be
1107
                 *            matched exactly by the values in the DB).
1108
                 * @return Board location description
1109
                 */
1110
                Optional<BoardLocation> getBoardByIPAddress(@IPAddress String address);
1111

1112
                /**
1113
                 * @return The IP address of the BMP of the root board of the machine.
1114
                 */
1115
                String getRootBoardBMPAddress();
1116

1117
                /** @return The boards supported by the machine. */
1118
                List<Integer> getBoardNumbers();
1119

1120
                /** @return The IDs of boards currently available to be allocated. */
1121
                List<Integer> getAvailableBoards();
1122

1123
                /**
1124
                 * Get the address of a particular BMP of a machine.
1125
                 *
1126
                 * @param bmp
1127
                 *            The BMP coordinates (cabinet, frame).
1128
                 * @return The IP address of the BMP.
1129
                 */
1130
                String getBMPAddress(@Valid BMPCoords bmp);
1131

1132
                /**
1133
                 * Get the board numbers managed by a particular BMP of a machine.
1134
                 *
1135
                 * @param bmp
1136
                 *            The BMP coordinates( cabinet, frame).
1137
                 * @return The board numbers managed by that BMP.
1138
                 */
1139
                List<Integer> getBoardNumbers(@Valid BMPCoords bmp);
1140
        }
1141

1142
        /**
1143
         * Describes the locations of boards in a machine. Note that instances of
1144
         * this class are expected to be fully instantiated; reading from them will
1145
         * <em>not</em> touch the database.
1146
         *
1147
         * @author Donal Fellows
1148
         */
1149
        interface BoardLocation {
1150
                /**
1151
                 * Get the location of the characteristic chip of a board. This is
1152
                 * usually the root chip of the board.
1153
                 *
1154
                 * @return chip location, in <em>global</em> (whole machine) coordinates
1155
                 */
1156
                ChipLocation getBoardChip();
1157

1158
                /**
1159
                 * Get the location of this board location relative to another global
1160
                 * location (the global location of the root chip of an allocation).
1161
                 *
1162
                 * @param rootChip
1163
                 *            The global location of the root chip of an allocation that
1164
                 *            we are converting this board location to be relative to.
1165
                 * @return chip location, in <em>relative</em> (single job) coordinates
1166
                 */
1167
                ChipLocation getChipRelativeTo(@NotNull ChipLocation rootChip);
1168

1169
                /**
1170
                 * What machine is the board on?
1171
                 *
1172
                 * @return name of machine
1173
                 */
1174
                String getMachine();
1175

1176
                /**
1177
                 * Where is the board logically within its machine?
1178
                 *
1179
                 * @return a triad location descriptor
1180
                 */
1181
                BoardCoordinates getLogical();
1182

1183
                /**
1184
                 * Where is the board physically in its machine?
1185
                 *
1186
                 * @return a cabinet/frame/board triple
1187
                 */
1188
                BoardPhysicalCoordinates getPhysical();
1189

1190
                /**
1191
                 * Where is the chip of interest? Usually the root chip of the board.
1192
                 *
1193
                 * @return a chip location, in <em>global</em> (whole machine)
1194
                 *         coordinates
1195
                 */
1196
                ChipLocation getChip();
1197

1198
                /**
1199
                 * What job is the board allocated to? May be {@code null} for an
1200
                 * unallocated board.
1201
                 *
1202
                 * @return a limited version of a job.
1203
                 */
1204
                Job getJob();
1205
        }
1206

1207
        /** A view of part of a machine that is allocated to a job. */
1208
        interface SubMachine {
1209
                /** @return The machine that this sub-machine is part of. */
1210
                Machine getMachine();
1211

1212
                /** @return The root X coordinate of this sub-machine. */
1213
                int getRootX();
1214

1215
                /** @return The root Y coordinate of this sub-machine. */
1216
                int getRootY();
1217

1218
                /** @return The root Z coordinate of this sub-machine. */
1219
                int getRootZ();
1220

1221
                /** @return The width of this sub-machine, in triads. */
1222
                int getWidth();
1223

1224
                /** @return The height of this sub-machine, in triads. */
1225
                int getHeight();
1226

1227
                /**
1228
                 * @return The depth of this sub-machine. 1 (single board) or 3 (by
1229
                 *         triad)
1230
                 */
1231
                int getDepth();
1232

1233
                /** @return The connection details of this sub-machine. */
1234
                List<ConnectionInfo> getConnections();
1235

1236
                /** @return The board locations of this sub-machine. */
1237
                List<BoardCoordinates> getBoards();
1238

1239
                /** @return Whether this sub-machine is switched on. */
1240
                PowerState getPower();
1241

1242
                /**
1243
                 * Set whether this sub-machine is switched on. Note that actually
1244
                 * changing the power of a sub-machine can take some time.
1245
                 *
1246
                 * @param powerState
1247
                 *            What to set the power state to.
1248
                 */
1249
                void setPower(@NotNull PowerState powerState);
1250
        }
1251
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc