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

SpiNNakerManchester / JavaSpiNNaker / 13770791693

10 Mar 2025 05:18PM UTC coverage: 38.345% (-0.04%) from 38.381%
13770791693

push

github

rowleya
Style fixes

1 of 1 new or added line in 1 file covered. (100.0%)

879 existing lines in 25 files now uncovered.

9191 of 23969 relevant lines covered (38.35%)

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.CoreLocation;
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.machine.tags.IPTag;
71
import uk.ac.manchester.spinnaker.protocols.FastDataIn;
72
import uk.ac.manchester.spinnaker.protocols.download.Downloader;
73
import uk.ac.manchester.spinnaker.spalloc.messages.BoardCoordinates;
74
import uk.ac.manchester.spinnaker.spalloc.messages.BoardPhysicalCoordinates;
75
import uk.ac.manchester.spinnaker.transceiver.ProcessException;
76
import uk.ac.manchester.spinnaker.transceiver.SpinnmanException;
77
import uk.ac.manchester.spinnaker.transceiver.TransceiverInterface;
78
import uk.ac.manchester.spinnaker.utils.UsedInJavadocOnly;
79
import uk.ac.manchester.spinnaker.utils.validation.IPAddress;
80

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

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

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

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

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

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

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

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

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

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

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

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

312
        /** Purge the cache of what boards are down. */
313
        void purgeDownCache();
314

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

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

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

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

375
                /**
376
                 * Get the area. The area is the number of boards required.
377
                 *
378
                 * @return The number of boards requested by the job.
379
                 */
380
                public abstract int getArea();
381

382
                abstract <T> T doVisit(CreateVisitor<T> visitor);
383
        }
384

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

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

407
                @Override
408
                <T> T doVisit(CreateVisitor<T> visitor) {
409
                        return visitor.numBoards(this);
3✔
410
                }
411

412
                @Override
413
                public int getArea() {
414
                        return numBoards;
3✔
415
                }
416
        }
417

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

430
                /** Height requested, in triads. */
431
                @ValidTriadHeight
432
                public final int height;
433

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

452
                @Override
453
                <T> T doVisit(CreateVisitor<T> visitor) {
454
                        return visitor.dimensions(this);
3✔
455
                }
456

457
                @Override
458
                public int getArea() {
459
                        return width * height;
3✔
460
                }
461
        }
462

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

469
                /** The physical coordinates, or {@code null}. */
470
                @Valid
471
                public final PhysicalCoords physical;
472

473
                /** The network coordinates, or {@code null}. */
474
                @IPAddress(nullOK = true)
475
                public final String ip;
476

477
                private HasBoardCoords(TriadCoords triad, PhysicalCoords physical,
478
                                String ip, Integer maxDeadBoards) {
479
                        super(maxDeadBoards);
3✔
480
                        this.triad = triad;
3✔
481
                        this.physical = physical;
3✔
482
                        this.ip = ip;
3✔
483
                }
3✔
484

485
                private static int get(Integer value) {
UNCOV
486
                        return Objects.nonNull(value) ? value : 0;
×
487
                }
488

489
                @Keep
490
                @AssertTrue(message = "a method of locating a board must be provided")
491
                private boolean isLocated() {
UNCOV
492
                        return nonNull(triad) || nonNull(physical) || nonNull(ip);
×
493
                }
494
        }
495

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

505
                /** Height requested, in triads. */
506
                @ValidTriadHeight
507
                public final int height;
508

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

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

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

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

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

628
                private CreateDimensionsAt(int width, int height,
629
                                PhysicalCoords physical, Integer maxDeadBoards) {
UNCOV
630
                        super(null, physical, null, maxDeadBoards);
×
UNCOV
631
                        this.width = width;
×
UNCOV
632
                        this.height = height;
×
UNCOV
633
                }
×
634

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

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

691
                @Override
692
                <T> T doVisit(CreateVisitor<T> visitor) {
693
                        return visitor.dimensionsAt(this);
3✔
694
                }
695

696
                @Override
697
                public int getArea() {
698
                        return width * height * TRIAD_DEPTH;
3✔
699
                }
700
        }
701

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

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

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

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

753
                @Override
754
                <T> T doVisit(CreateVisitor<T> visitor) {
755
                        return visitor.board(this);
3✔
756
                }
757

758
                @Override
759
                public int getArea() {
760
                        return 1;
3✔
761
                }
762
        }
763

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

780
                /**
781
                 * Visit a descriptor.
782
                 *
783
                 * @param createDimensionsAt
784
                 *            The descriptor.
785
                 * @return The result of the visiting.
786
                 */
787
                T dimensionsAt(@NotNull CreateDimensionsAt createDimensionsAt);
788

789
                /**
790
                 * Visit a descriptor.
791
                 *
792
                 * @param createDimensions
793
                 *            The descriptor.
794
                 * @return The result of the visiting.
795
                 */
796
                T dimensions(@NotNull CreateDimensions createDimensions);
797

798
                /**
799
                 * Visit a descriptor.
800
                 *
801
                 * @param createBoard
802
                 *            The descriptor.
803
                 * @return The result of the visiting.
804
                 */
805
                T board(@NotNull CreateBoard createBoard);
806
        }
807

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

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

840
                /**
841
                 * Update the keepalive.
842
                 *
843
                 * @param keepaliveAddress
844
                 *            Where was the access from.
845
                 */
846
                void access(@NotNull @IPAddress String keepaliveAddress);
847

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

857
                /**
858
                 * Power a job on or off.
859
                 *
860
                 * @param power True for on, False for off
861
                 */
862
                void setPower(boolean power);
863

864
                /**
865
                 * @return The state of the job.
866
                 */
867
                JobState getState();
868

869
                /**
870
                 * @return When the job started.
871
                 */
872
                Instant getStartTime();
873

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

881
                /**
882
                 * @return Time of the last keepalive event.
883
                 */
884
                Instant getKeepaliveTimestamp();
885

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

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

899
                /**
900
                 * @return When the job finished. {@link Optional#empty() empty()} if
901
                 *         the job is not yet finished.
902
                 */
903
                Optional<Instant> getFinishTime();
904

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

911
                /**
912
                 * @return The (sub-)machine allocated to the job.
913
                 *         {@link Optional#empty() empty()} if no resources allocated.
914
                 */
915
                Optional<SubMachine> getMachine();
916

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

929
                /**
930
                 * @return The absolute location of root chip. {@link Optional#empty()
931
                 *         empty()} if no resources allocated.
932
                 */
933
                Optional<ChipLocation> getRootChip();
934

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

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

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

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

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

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

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

1000
                /**
1001
                 * Get a FastDataIn protocol instance for an Ethernet within a job.
1002
                 *
1003
                 * @param gathererCore The core that will do the gathering.
1004
                 * @param iptag The IPTag to use.
1005
                 * @return A FastDataIn instance.
1006
                 * @throws ProcessException if there is an issue setting up the tag.
1007
                 * @throws IOException if there is an issue communicating.
1008
                 * @throws InterruptedException if the operation is interrupted.
1009
                 */
1010
                FastDataIn getFastDataIn(CoreLocation gathererCore, IPTag iptag)
1011
                                throws ProcessException, IOException, InterruptedException;
1012

1013
                /**
1014
                 * Get a Downloader protocol instance for an Ethernet within a job.
1015
                 *
1016
                 * @param iptag The IPTag to use.
1017
                 * @return A Downloader instance.
1018
                 * @throws ProcessException if there is an issue setting up the tag.
1019
                 * @throws IOException if there is an issue communicating.
1020
                 * @throws InterruptedException if the operation is interrupted.
1021
                 */
1022
                Downloader getDownloader(IPTag iptag)
1023
                                throws ProcessException, IOException, InterruptedException;
1024
        }
1025

1026
        /**
1027
         * Describes a list of jobs known to the allocator.
1028
         *
1029
         * @author Donal Fellows
1030
         */
1031
        interface Jobs extends Waitable {
1032
                /**
1033
                 * @return The job IDs.
1034
                 */
1035
                List<Integer> ids();
1036

1037
                /**
1038
                 * @return The jobs. Simplified view only. (No keepalive host or owner
1039
                 *         information.)
1040
                 */
1041
                List<Job> jobs();
1042

1043
                /**
1044
                 * @param duration
1045
                 *            How long to wait for a change.
1046
                 * @return The set of jobs that have changed.
1047
                 */
1048
                Collection<Integer> getChanged(Duration duration);
1049
        }
1050

1051
        /**
1052
         * Describes a particular machine known to the allocator. Must implement
1053
         * equality by ID or name (both are unique).
1054
         *
1055
         * @author Donal Fellows
1056
         */
1057
        interface Machine extends Waitable {
1058
                /** @return The ID of the machine. Unique. */
1059
                int getId();
1060

1061
                /** @return The name of the machine. Unique. */
1062
                String getName();
1063

1064
                /** @return The tags associated with the machine. */
1065
                Set<String> getTags();
1066

1067
                /** @return The width of the machine. */
1068
                int getWidth();
1069

1070
                /** @return The height of the machine. */
1071
                int getHeight();
1072

1073
                /** @return Whether the machine wraps in the horizontal direction. */
1074
                boolean isHorizonallyWrapped();
1075

1076
                /** @return Whether the machine wraps in the vertical direction. */
1077
                boolean isVerticallyWrapped();
1078

1079
                /** @return Whether this machine is currently in service. */
1080
                boolean isInService();
1081

1082
                /**
1083
                 * The IDs of boards marked as dead or otherwise taken out of service.
1084
                 *
1085
                 * @return A list of boards. Not modifiable.
1086
                 */
1087
                List<BoardCoords> getDeadBoards();
1088

1089
                /**
1090
                 * The links within the machine that are marked as dead or otherwise
1091
                 * taken out of service. Note that this does not include links that lead
1092
                 * out of the machine.
1093
                 *
1094
                 * @return A list of links. Not modifiable.
1095
                 */
1096
                List<DownLink> getDownLinks();
1097

1098
                /**
1099
                 * Get a description of the location of a board given the global
1100
                 * coordinates of a chip on it.
1101
                 *
1102
                 * @param chipLocation
1103
                 *            Global chip coordinates.
1104
                 * @return Board location description
1105
                 */
1106
                Optional<BoardLocation> getBoardByChip(
1107
                                @Valid @NotNull HasChipLocation chipLocation);
1108

1109
                /**
1110
                 * Get a description of the location of a board given the physical
1111
                 * coordinates of the board.
1112
                 *
1113
                 * @param coords
1114
                 *            PhysicalCoordinates
1115
                 * @return Board location description
1116
                 */
1117
                Optional<BoardLocation> getBoardByPhysicalCoords(
1118
                                @Valid @NotNull PhysicalCoords coords);
1119

1120
                /**
1121
                 * Get a description of the location of a board given the triad
1122
                 * coordinates of the board.
1123
                 *
1124
                 * @param coords
1125
                 *            Triad coordinates.
1126
                 * @return Board location description
1127
                 */
1128
                Optional<BoardLocation> getBoardByLogicalCoords(
1129
                                @Valid @NotNull TriadCoords coords);
1130

1131
                /**
1132
                 * Get a description of the location of a board given the address of its
1133
                 * ethernet chip.
1134
                 *
1135
                 * @param address
1136
                 *            IP address of the board (in {@code 0.0.0.0} form; will be
1137
                 *            matched exactly by the values in the DB).
1138
                 * @return Board location description
1139
                 */
1140
                Optional<BoardLocation> getBoardByIPAddress(@IPAddress String address);
1141

1142
                /**
1143
                 * @return The IP address of the BMP of the root board of the machine.
1144
                 */
1145
                String getRootBoardBMPAddress();
1146

1147
                /** @return The boards supported by the machine. */
1148
                List<Integer> getBoardNumbers();
1149

1150
                /** @return The IDs of boards currently available to be allocated. */
1151
                List<Integer> getAvailableBoards();
1152

1153
                /**
1154
                 * Get the address of a particular BMP of a machine.
1155
                 *
1156
                 * @param bmp
1157
                 *            The BMP coordinates (cabinet, frame).
1158
                 * @return The IP address of the BMP.
1159
                 */
1160
                String getBMPAddress(@Valid BMPCoords bmp);
1161

1162
                /**
1163
                 * Get the board numbers managed by a particular BMP of a machine.
1164
                 *
1165
                 * @param bmp
1166
                 *            The BMP coordinates( cabinet, frame).
1167
                 * @return The board numbers managed by that BMP.
1168
                 */
1169
                List<Integer> getBoardNumbers(@Valid BMPCoords bmp);
1170
        }
1171

1172
        /**
1173
         * Describes the locations of boards in a machine. Note that instances of
1174
         * this class are expected to be fully instantiated; reading from them will
1175
         * <em>not</em> touch the database.
1176
         *
1177
         * @author Donal Fellows
1178
         */
1179
        interface BoardLocation {
1180
                /**
1181
                 * Get the location of the characteristic chip of a board. This is
1182
                 * usually the root chip of the board.
1183
                 *
1184
                 * @return chip location, in <em>global</em> (whole machine) coordinates
1185
                 */
1186
                ChipLocation getBoardChip();
1187

1188
                /**
1189
                 * Get the location of this board location relative to another global
1190
                 * location (the global location of the root chip of an allocation).
1191
                 *
1192
                 * @param rootChip
1193
                 *            The global location of the root chip of an allocation that
1194
                 *            we are converting this board location to be relative to.
1195
                 * @return chip location, in <em>relative</em> (single job) coordinates
1196
                 */
1197
                ChipLocation getChipRelativeTo(@NotNull ChipLocation rootChip);
1198

1199
                /**
1200
                 * What machine is the board on?
1201
                 *
1202
                 * @return name of machine
1203
                 */
1204
                String getMachine();
1205

1206
                /**
1207
                 * Where is the board logically within its machine?
1208
                 *
1209
                 * @return a triad location descriptor
1210
                 */
1211
                BoardCoordinates getLogical();
1212

1213
                /**
1214
                 * Where is the board physically in its machine?
1215
                 *
1216
                 * @return a cabinet/frame/board triple
1217
                 */
1218
                BoardPhysicalCoordinates getPhysical();
1219

1220
                /**
1221
                 * Where is the chip of interest? Usually the root chip of the board.
1222
                 *
1223
                 * @return a chip location, in <em>global</em> (whole machine)
1224
                 *         coordinates
1225
                 */
1226
                ChipLocation getChip();
1227

1228
                /**
1229
                 * What job is the board allocated to? May be {@code null} for an
1230
                 * unallocated board.
1231
                 *
1232
                 * @return a limited version of a job.
1233
                 */
1234
                Job getJob();
1235
        }
1236

1237
        /** A view of part of a machine that is allocated to a job. */
1238
        interface SubMachine {
1239
                /** @return The machine that this sub-machine is part of. */
1240
                Machine getMachine();
1241

1242
                /** @return The root X coordinate of this sub-machine. */
1243
                int getRootX();
1244

1245
                /** @return The root Y coordinate of this sub-machine. */
1246
                int getRootY();
1247

1248
                /** @return The root Z coordinate of this sub-machine. */
1249
                int getRootZ();
1250

1251
                /** @return The width of this sub-machine, in triads. */
1252
                int getWidth();
1253

1254
                /** @return The height of this sub-machine, in triads. */
1255
                int getHeight();
1256

1257
                /**
1258
                 * @return The depth of this sub-machine. 1 (single board) or 3 (by
1259
                 *         triad)
1260
                 */
1261
                int getDepth();
1262

1263
                /** @return The connection details of this sub-machine. */
1264
                List<ConnectionInfo> getConnections();
1265

1266
                /** @return The board locations of this sub-machine. */
1267
                List<BoardCoordinates> getBoards();
1268

1269
                /** @return Whether this sub-machine is switched on. */
1270
                PowerState getPower();
1271

1272
                /**
1273
                 * Set whether this sub-machine is switched on. Note that actually
1274
                 * changing the power of a sub-machine can take some time.
1275
                 *
1276
                 * @param powerState
1277
                 *            What to set the power state to.
1278
                 */
1279
                void setPower(@NotNull PowerState powerState);
1280
        }
1281
}
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