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

SpiNNakerManchester / JavaSpiNNaker / 13181910460

06 Feb 2025 03:14PM UTC coverage: 38.583% (+0.001%) from 38.582%
13181910460

push

github

rowleya
Fix tests too

9184 of 23803 relevant lines covered (38.58%)

1.16 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
import com.google.errorprone.annotations.MustBeClosed;
46

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1244
                /**
1245
                 * Set whether this sub-machine is switched on. Note that actually
1246
                 * changing the power of a sub-machine can take some time.
1247
                 *
1248
                 * @param powerState
1249
                 *            What to set the power state to.
1250
                 */
1251
                void setPower(@NotNull PowerState powerState);
1252
        }
1253
}
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