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

SpiNNakerManchester / JavaSpiNNaker / 6310285782

26 Sep 2023 08:47AM UTC coverage: 36.367% (-0.5%) from 36.866%
6310285782

Pull #658

github

dkfellows
Merge branch 'master' into java-17
Pull Request #658: Update Java version to 17 and JEE to 9

1675 of 1675 new or added lines in 266 files covered. (100.0%)

8368 of 23010 relevant lines covered (36.37%)

0.36 hits per line

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

47.69
/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.time.Duration;
26
import java.time.Instant;
27
import java.util.Collection;
28
import java.util.List;
29
import java.util.Map;
30
import java.util.Objects;
31
import java.util.Optional;
32
import java.util.Set;
33

34
import org.springframework.security.access.prepost.PostFilter;
35
import org.springframework.security.access.prepost.PreAuthorize;
36

37
import com.google.errorprone.annotations.Keep;
38

39
import jakarta.validation.Valid;
40
import jakarta.validation.constraints.AssertTrue;
41
import jakarta.validation.constraints.NotNull;
42
import jakarta.validation.constraints.Positive;
43
import jakarta.validation.constraints.PositiveOrZero;
44
import uk.ac.manchester.spinnaker.alloc.compat.V1CompatService;
45
import uk.ac.manchester.spinnaker.alloc.model.BoardCoords;
46
import uk.ac.manchester.spinnaker.alloc.model.ConnectionInfo;
47
import uk.ac.manchester.spinnaker.alloc.model.DownLink;
48
import uk.ac.manchester.spinnaker.alloc.model.JobDescription;
49
import uk.ac.manchester.spinnaker.alloc.model.JobListEntryRecord;
50
import uk.ac.manchester.spinnaker.alloc.model.JobState;
51
import uk.ac.manchester.spinnaker.alloc.model.MachineDescription;
52
import uk.ac.manchester.spinnaker.alloc.model.MachineListEntryRecord;
53
import uk.ac.manchester.spinnaker.alloc.model.PowerState;
54
import uk.ac.manchester.spinnaker.alloc.proxy.ProxyCore;
55
import uk.ac.manchester.spinnaker.alloc.security.Permit;
56
import uk.ac.manchester.spinnaker.alloc.web.IssueReportRequest;
57
import uk.ac.manchester.spinnaker.machine.ChipLocation;
58
import uk.ac.manchester.spinnaker.machine.HasChipLocation;
59
import uk.ac.manchester.spinnaker.machine.HasCoreLocation;
60
import uk.ac.manchester.spinnaker.machine.ValidX;
61
import uk.ac.manchester.spinnaker.machine.ValidY;
62
import uk.ac.manchester.spinnaker.machine.board.BMPCoords;
63
import uk.ac.manchester.spinnaker.machine.board.PhysicalCoords;
64
import uk.ac.manchester.spinnaker.machine.board.TriadCoords;
65
import uk.ac.manchester.spinnaker.machine.board.ValidTriadHeight;
66
import uk.ac.manchester.spinnaker.machine.board.ValidTriadWidth;
67
import uk.ac.manchester.spinnaker.spalloc.messages.BoardCoordinates;
68
import uk.ac.manchester.spinnaker.spalloc.messages.BoardPhysicalCoordinates;
69
import uk.ac.manchester.spinnaker.utils.UsedInJavadocOnly;
70
import uk.ac.manchester.spinnaker.utils.validation.IPAddress;
71

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

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

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

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

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

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

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

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

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

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

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

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

299
        /** Purge the cache of what boards are down. */
300
        void purgeDownCache();
301

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

322
        /**
323
         * Describes what sort of request to create a job this is.
324
         *
325
         * @see CreateNumBoards
326
         * @see CreateDimensions
327
         * @see CreateDimensionsAt
328
         * @see CreateBoard
329
         */
330
        abstract sealed class CreateDescriptor
331
                        permits CreateDimensions, CreateNumBoards, HasBoardCoords {
332
                /**
333
                 * The maximum number of dead boards tolerated in the allocation.
334
                 * Ignored when asking for a single board.
335
                 */
336
                @PositiveOrZero(message = "maxDeadBoards must not be negative")
337
                public final int maxDead;
338

339
                /**
340
                 * Only known subclasses permitted.
341
                 *
342
                 * @param maxDeadBoards
343
                 *            The maximum number of dead boards. {@code null} is
344
                 *            equivalent to 0.
345
                 */
346
                private CreateDescriptor(Integer maxDeadBoards) {
1✔
347
                        this.maxDead = isNull(maxDeadBoards) ? 0 : maxDeadBoards;
1✔
348
                }
1✔
349

350
                /**
351
                 * Apply a visitor to this descriptor.
352
                 *
353
                 * @param <T>
354
                 *            The type of the result of the visiting.
355
                 * @param visitor
356
                 *            The visitor to apply.
357
                 * @return The result computed by the visitor.
358
                 */
359
                public final <T> T visit(CreateVisitor<T> visitor) {
360
                        return doVisit(requireNonNull(visitor));
1✔
361
                }
362

363
                /**
364
                 * Get the area. The area is the number of boards required.
365
                 *
366
                 * @return The number of boards requested by the job.
367
                 */
368
                public abstract int getArea();
369

370
                abstract <T> T doVisit(CreateVisitor<T> visitor);
371
        }
372

373
        /**
374
         * A request for a number of boards.
375
         */
376
        final class CreateNumBoards extends CreateDescriptor {
377
                /** The number of boards requested. */
378
                @Positive(message = "number of boards to request must be positive")
379
                public final int numBoards;
380

381
                /**
382
                 * Request a count of boards. The service <em>may</em> over-allocate.
383
                 *
384
                 * @param numBoards
385
                 *            The number of boards desired.
386
                 * @param maxDeadBoards
387
                 *            The number of dead boards that can be tolerated within
388
                 *            that.
389
                 */
390
                public CreateNumBoards(int numBoards, Integer maxDeadBoards) {
391
                        super(maxDeadBoards);
1✔
392
                        this.numBoards = numBoards;
1✔
393
                }
1✔
394

395
                @Override
396
                <T> T doVisit(CreateVisitor<T> visitor) {
397
                        return visitor.numBoards(this);
1✔
398
                }
399

400
                @Override
401
                public int getArea() {
402
                        return numBoards;
1✔
403
                }
404
        }
405

406
        /**
407
         * A request for a rectangle of boards. This is expressed in boards for
408
         * reasons relating to the legacy API.
409
         *
410
         * @see V1CompatService
411
         */
412
        @UsedInJavadocOnly(V1CompatService.class)
413
        final class CreateDimensions extends CreateDescriptor {
414
                /** Width requested, in triads. */
415
                @ValidTriadWidth
416
                public final int width;
417

418
                /** Height requested, in triads. */
419
                @ValidTriadHeight
420
                public final int height;
421

422
                /**
423
                 * Request a rectangle of boards. The service <em>may</em>
424
                 * over-allocate.
425
                 *
426
                 * @param width
427
                 *            The width of rectangle to request, in triads.
428
                 * @param height
429
                 *            The height of rectangle to request, in triads.
430
                 * @param maxDeadBoards
431
                 *            The number of dead boards that can be tolerated in that
432
                 *            rectangle.
433
                 */
434
                public CreateDimensions(int width, int height, Integer maxDeadBoards) {
435
                        super(maxDeadBoards);
1✔
436
                        this.width = width;
1✔
437
                        this.height = height;
1✔
438
                }
1✔
439

440
                @Override
441
                <T> T doVisit(CreateVisitor<T> visitor) {
442
                        return visitor.dimensions(this);
1✔
443
                }
444

445
                @Override
446
                public int getArea() {
447
                        return width * height;
1✔
448
                }
449
        }
450

451
        /** Some requests have the locations of boards. */
452
        abstract sealed class HasBoardCoords
453
                        extends CreateDescriptor permits CreateDimensionsAt, CreateBoard {
454
                /** The logical coordinates, or {@code null}. */
455
                @Valid
456
                public final TriadCoords triad;
457

458
                /** The physical coordinates, or {@code null}. */
459
                @Valid
460
                public final PhysicalCoords physical;
461

462
                /** The network coordinates, or {@code null}. */
463
                @IPAddress(nullOK = true)
464
                public final String ip;
465

466
                private HasBoardCoords(TriadCoords triad, PhysicalCoords physical,
467
                                String ip, Integer maxDeadBoards) {
468
                        super(maxDeadBoards);
1✔
469
                        this.triad = triad;
1✔
470
                        this.physical = physical;
1✔
471
                        this.ip = ip;
1✔
472
                }
1✔
473

474
                private static int get(Integer value) {
475
                        return Objects.nonNull(value) ? value : 0;
×
476
                }
477

478
                @Keep
479
                @AssertTrue(message = "a method of locating a board must be provided")
480
                private boolean isLocated() {
481
                        return nonNull(triad) || nonNull(physical) || nonNull(ip);
×
482
                }
483
        }
484

485
        /**
486
         * A request for a rectangle of triads rooted at a particular triad. No
487
         * option for using physical coordinates is supported with this method.
488
         */
489
        final class CreateDimensionsAt extends HasBoardCoords {
490
                /** Width requested, in triads. */
491
                @ValidTriadWidth
492
                public final int width;
493

494
                /** Height requested, in triads. */
495
                @ValidTriadHeight
496
                public final int height;
497

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

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

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

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

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

617
                private CreateDimensionsAt(int width, int height,
618
                                PhysicalCoords physical, Integer maxDeadBoards) {
619
                        super(null, physical, null, maxDeadBoards);
×
620
                        this.width = width;
×
621
                        this.height = height;
×
622
                }
×
623

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

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

680
                @Override
681
                <T> T doVisit(CreateVisitor<T> visitor) {
682
                        return visitor.dimensionsAt(this);
1✔
683
                }
684

685
                @Override
686
                public int getArea() {
687
                        return width * height * TRIAD_DEPTH;
1✔
688
                }
689
        }
690

691
        /**
692
         * A request for a specific board.
693
         */
694
        final class CreateBoard extends HasBoardCoords {
695
                private CreateBoard(TriadCoords triad, PhysicalCoords physical,
696
                                String ip) {
697
                        super(triad, physical, ip, null);
1✔
698
                }
1✔
699

700
                /**
701
                 * Create a request for a specific board.
702
                 *
703
                 * @param x
704
                 *            The X coordinate of the board.
705
                 * @param y
706
                 *            The Y coordinate of the board.
707
                 * @param z
708
                 *            The Z coordinate of the board.
709
                 * @return Descriptor
710
                 */
711
                public static CreateBoard triad(int x, int y, int z) {
712
                        return new CreateBoard(new TriadCoords(x, y, z), null, null);
1✔
713
                }
714

715
                /**
716
                 * Create a request for a specific board.
717
                 *
718
                 * @param cabinet
719
                 *            The cabinet number of the board.
720
                 * @param frame
721
                 *            The frame number of the board.
722
                 * @param board
723
                 *            The board number of the board.
724
                 * @return Descriptor
725
                 */
726
                public static CreateBoard physical(int cabinet, int frame, int board) {
727
                        return new CreateBoard(null,
×
728
                                        new PhysicalCoords(cabinet, frame, board), null);
729
                }
730

731
                /**
732
                 * Create a request for a specific board.
733
                 *
734
                 * @param ip
735
                 *            The network address of the board.
736
                 * @return Descriptor
737
                 */
738
                public static CreateBoard address(@IPAddress String ip) {
739
                        return new CreateBoard(null, null, ip);
×
740
                }
741

742
                @Override
743
                <T> T doVisit(CreateVisitor<T> visitor) {
744
                        return visitor.board(this);
1✔
745
                }
746

747
                @Override
748
                public int getArea() {
749
                        return 1;
1✔
750
                }
751
        }
752

753
        /**
754
         * Visitor for {@link CreateDescriptor}.
755
         *
756
         * @param <T>
757
         *            The type of the result of visiting.
758
         */
759
        interface CreateVisitor<T> {
760
                /**
761
                 * Visit a descriptor.
762
                 *
763
                 * @param createNumBoards
764
                 *            The descriptor.
765
                 * @return The result of the visiting.
766
                 */
767
                default T numBoards(@NotNull CreateNumBoards createNumBoards) {
768
                        return null;
×
769
                }
770

771
                /**
772
                 * Visit a descriptor.
773
                 *
774
                 * @param createDimensionsAt
775
                 *            The descriptor.
776
                 * @return The result of the visiting.
777
                 */
778
                default T dimensionsAt(@NotNull CreateDimensionsAt createDimensionsAt) {
779
                        return null;
×
780
                }
781

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

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

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

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

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

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

854
                /**
855
                 * @return The state of the job.
856
                 */
857
                JobState getState();
858

859
                /**
860
                 * @return When the job started.
861
                 */
862
                Instant getStartTime();
863

864
                /**
865
                 * @return Host address that issued last keepalive event, or
866
                 *         {@link Optional#empty() empty()} if this information is not
867
                 *         available to the current user.
868
                 */
869
                Optional<String> getKeepaliveHost();
870

871
                /**
872
                 * @return Time of the last keepalive event.
873
                 */
874
                Instant getKeepaliveTimestamp();
875

876
                /**
877
                 * @return The creator of the job. {@link Optional#empty() empty()} if
878
                 *         this is not available to the current user.
879
                 */
880
                Optional<String> getOwner();
881

882
                /**
883
                 * @return The serialized original request to create the job.
884
                 *         {@link Optional#empty() empty()} if this is not available to
885
                 *         the current user.
886
                 */
887
                Optional<byte[]> getOriginalRequest();
888

889
                /**
890
                 * @return When the job finished. {@link Optional#empty() empty()} if
891
                 *         the job is not yet finished.
892
                 */
893
                Optional<Instant> getFinishTime();
894

895
                /**
896
                 * @return Why the job died. Might be {@link Optional#empty() empty()}
897
                 *         if this isn't known (including if the job is alive).
898
                 */
899
                Optional<String> getReason();
900

901
                /**
902
                 * @return The (sub-)machine allocated to the job.
903
                 *         {@link Optional#empty() empty()} if no resources allocated.
904
                 */
905
                Optional<SubMachine> getMachine();
906

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

919
                /**
920
                 * @return The absolute location of root chip. {@link Optional#empty()
921
                 *         empty()} if no resources allocated.
922
                 */
923
                Optional<ChipLocation> getRootChip();
924

925
                /**
926
                 * @return the allocated width of the job's rectangle of triads, or
927
                 *         {@link Optional#empty() empty()} if not allocated (or not
928
                 *         known).
929
                 */
930
                Optional<Integer> getWidth();
931

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

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

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

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

968
                /**
969
                 * Note that a proxy has been dropped from the job and doesn't need to
970
                 * be remembered any more.
971
                 *
972
                 * @param proxy
973
                 *            The proxy.
974
                 */
975
                void forgetProxy(ProxyCore proxy);
976
        }
977

978
        /**
979
         * Describes a list of jobs known to the allocator.
980
         *
981
         * @author Donal Fellows
982
         */
983
        interface Jobs extends Waitable {
984
                /**
985
                 * @return The job IDs.
986
                 */
987
                List<Integer> ids();
988

989
                /**
990
                 * @return The jobs. Simplified view only. (No keepalive host or owner
991
                 *         information.)
992
                 */
993
                List<Job> jobs();
994

995
                /**
996
                 * @param duration
997
                 *            How long to wait for a change.
998
                 * @return The set of jobs that have changed.
999
                 */
1000
                Collection<Integer> getChanged(Duration duration);
1001
        }
1002

1003
        /**
1004
         * Describes a particular machine known to the allocator. Must implement
1005
         * equality by ID or name (both are unique).
1006
         *
1007
         * @author Donal Fellows
1008
         */
1009
        interface Machine extends Waitable {
1010
                /** @return The ID of the machine. Unique. */
1011
                int getId();
1012

1013
                /** @return The name of the machine. Unique. */
1014
                String getName();
1015

1016
                /** @return The tags associated with the machine. */
1017
                Set<String> getTags();
1018

1019
                /** @return The width of the machine. */
1020
                int getWidth();
1021

1022
                /** @return The height of the machine. */
1023
                int getHeight();
1024

1025
                /** @return Whether the machine wraps in the horizontal direction. */
1026
                boolean isHorizonallyWrapped();
1027

1028
                /** @return Whether the machine wraps in the vertical direction. */
1029
                boolean isVerticallyWrapped();
1030

1031
                /** @return Whether this machine is currently in service. */
1032
                boolean isInService();
1033

1034
                /**
1035
                 * The IDs of boards marked as dead or otherwise taken out of service.
1036
                 *
1037
                 * @return A list of boards. Not modifiable.
1038
                 */
1039
                List<BoardCoords> getDeadBoards();
1040

1041
                /**
1042
                 * The links within the machine that are marked as dead or otherwise
1043
                 * taken out of service. Note that this does not include links that lead
1044
                 * out of the machine.
1045
                 *
1046
                 * @return A list of links. Not modifiable.
1047
                 */
1048
                List<DownLink> getDownLinks();
1049

1050
                /**
1051
                 * Get a description of the location of a board given the global
1052
                 * coordinates of a chip on it.
1053
                 *
1054
                 * @param chipLocation
1055
                 *            Global chip coordinates.
1056
                 * @return Board location description
1057
                 */
1058
                Optional<BoardLocation> getBoardByChip(
1059
                                @Valid @NotNull HasChipLocation chipLocation);
1060

1061
                /**
1062
                 * Get a description of the location of a board given the physical
1063
                 * coordinates of the board.
1064
                 *
1065
                 * @param coords
1066
                 *            PhysicalCoordinates
1067
                 * @return Board location description
1068
                 */
1069
                Optional<BoardLocation> getBoardByPhysicalCoords(
1070
                                @Valid @NotNull PhysicalCoords coords);
1071

1072
                /**
1073
                 * Get a description of the location of a board given the triad
1074
                 * coordinates of the board.
1075
                 *
1076
                 * @param coords
1077
                 *            Triad coordinates.
1078
                 * @return Board location description
1079
                 */
1080
                Optional<BoardLocation> getBoardByLogicalCoords(
1081
                                @Valid @NotNull TriadCoords coords);
1082

1083
                /**
1084
                 * Get a description of the location of a board given the address of its
1085
                 * ethernet chip.
1086
                 *
1087
                 * @param address
1088
                 *            IP address of the board (in {@code 0.0.0.0} form; will be
1089
                 *            matched exactly by the values in the DB).
1090
                 * @return Board location description
1091
                 */
1092
                Optional<BoardLocation> getBoardByIPAddress(@IPAddress String address);
1093

1094
                /**
1095
                 * @return The IP address of the BMP of the root board of the machine.
1096
                 */
1097
                String getRootBoardBMPAddress();
1098

1099
                /** @return The boards supported by the machine. */
1100
                List<Integer> getBoardNumbers();
1101

1102
                /** @return The IDs of boards currently available to be allocated. */
1103
                List<Integer> getAvailableBoards();
1104

1105
                /**
1106
                 * Get the address of a particular BMP of a machine.
1107
                 *
1108
                 * @param bmp
1109
                 *            The BMP coordinates (cabinet, frame).
1110
                 * @return The IP address of the BMP.
1111
                 */
1112
                String getBMPAddress(@Valid BMPCoords bmp);
1113

1114
                /**
1115
                 * Get the board numbers managed by a particular BMP of a machine.
1116
                 *
1117
                 * @param bmp
1118
                 *            The BMP coordinates( cabinet, frame).
1119
                 * @return The board numbers managed by that BMP.
1120
                 */
1121
                List<Integer> getBoardNumbers(@Valid BMPCoords bmp);
1122
        }
1123

1124
        /**
1125
         * Describes the locations of boards in a machine. Note that instances of
1126
         * this class are expected to be fully instantiated; reading from them will
1127
         * <em>not</em> touch the database.
1128
         *
1129
         * @author Donal Fellows
1130
         */
1131
        interface BoardLocation {
1132
                /**
1133
                 * Get the location of the characteristic chip of a board. This is
1134
                 * usually the root chip of the board.
1135
                 *
1136
                 * @return chip location, in <em>global</em> (whole machine) coordinates
1137
                 */
1138
                ChipLocation getBoardChip();
1139

1140
                /**
1141
                 * Get the location of this board location relative to another global
1142
                 * location (the global location of the root chip of an allocation).
1143
                 *
1144
                 * @param rootChip
1145
                 *            The global location of the root chip of an allocation that
1146
                 *            we are converting this board location to be relative to.
1147
                 * @return chip location, in <em>relative</em> (single job) coordinates
1148
                 */
1149
                ChipLocation getChipRelativeTo(@NotNull ChipLocation rootChip);
1150

1151
                /**
1152
                 * What machine is the board on?
1153
                 *
1154
                 * @return name of machine
1155
                 */
1156
                String getMachine();
1157

1158
                /**
1159
                 * Where is the board logically within its machine?
1160
                 *
1161
                 * @return a triad location descriptor
1162
                 */
1163
                BoardCoordinates getLogical();
1164

1165
                /**
1166
                 * Where is the board physically in its machine?
1167
                 *
1168
                 * @return a cabinet/frame/board triple
1169
                 */
1170
                BoardPhysicalCoordinates getPhysical();
1171

1172
                /**
1173
                 * Where is the chip of interest? Usually the root chip of the board.
1174
                 *
1175
                 * @return a chip location, in <em>global</em> (whole machine)
1176
                 *         coordinates
1177
                 */
1178
                ChipLocation getChip();
1179

1180
                /**
1181
                 * What job is the board allocated to? May be {@code null} for an
1182
                 * unallocated board.
1183
                 *
1184
                 * @return a limited version of a job.
1185
                 */
1186
                Job getJob();
1187
        }
1188

1189
        /** A view of part of a machine that is allocated to a job. */
1190
        interface SubMachine {
1191
                /** @return The machine that this sub-machine is part of. */
1192
                Machine getMachine();
1193

1194
                /** @return The root X coordinate of this sub-machine. */
1195
                int getRootX();
1196

1197
                /** @return The root Y coordinate of this sub-machine. */
1198
                int getRootY();
1199

1200
                /** @return The root Z coordinate of this sub-machine. */
1201
                int getRootZ();
1202

1203
                /** @return The width of this sub-machine, in triads. */
1204
                int getWidth();
1205

1206
                /** @return The height of this sub-machine, in triads. */
1207
                int getHeight();
1208

1209
                /**
1210
                 * @return The depth of this sub-machine. 1 (single board) or 3 (by
1211
                 *         triad)
1212
                 */
1213
                int getDepth();
1214

1215
                /** @return The connection details of this sub-machine. */
1216
                List<ConnectionInfo> getConnections();
1217

1218
                /** @return The board locations of this sub-machine. */
1219
                List<BoardCoordinates> getBoards();
1220

1221
                /** @return Whether this sub-machine is switched on. */
1222
                PowerState getPower();
1223

1224
                /**
1225
                 * Set whether this sub-machine is switched on. Note that actually
1226
                 * changing the power of a sub-machine can take some time.
1227
                 *
1228
                 * @param powerState
1229
                 *            What to set the power state to.
1230
                 */
1231
                void setPower(@NotNull PowerState powerState);
1232
        }
1233
}
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