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

SpiNNakerManchester / JavaSpiNNaker / 13070643287

31 Jan 2025 10:04AM UTC coverage: 38.643% (+0.01%) from 38.633%
13070643287

push

github

rowleya
Fix line length

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

281 existing lines in 9 files now uncovered.

9175 of 23743 relevant lines covered (38.64%)

1.16 hits per line

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

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

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

25
import java.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 javax.validation.Valid;
35
import javax.validation.constraints.AssertTrue;
36
import javax.validation.constraints.NotNull;
37
import javax.validation.constraints.Positive;
38
import javax.validation.constraints.PositiveOrZero;
39

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

304
        /** Purge the cache of what boards are down. */
305
        void purgeDownCache();
306

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

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

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

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

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

374
                abstract <T> T doVisit(CreateVisitor<T> visitor);
375
        }
376

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

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

399
                @Override
400
                <T> T doVisit(CreateVisitor<T> visitor) {
401
                        return visitor.numBoards(this);
3✔
402
                }
403

404
                @Override
405
                public int getArea() {
406
                        return numBoards;
3✔
407
                }
408
        }
409

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

422
                /** Height requested, in triads. */
423
                @ValidTriadHeight
424
                public final int height;
425

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

444
                @Override
445
                <T> T doVisit(CreateVisitor<T> visitor) {
446
                        return visitor.dimensions(this);
3✔
447
                }
448

449
                @Override
450
                public int getArea() {
451
                        return width * height;
3✔
452
                }
453
        }
454

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

461
                /** The physical coordinates, or {@code null}. */
462
                @Valid
463
                public final PhysicalCoords physical;
464

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

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

477
                private static int get(Integer value) {
UNCOV
478
                        return Objects.nonNull(value) ? value : 0;
×
479
                }
480

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

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

497
                /** Height requested, in triads. */
498
                @ValidTriadHeight
499
                public final int height;
500

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

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

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

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

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

620
                private CreateDimensionsAt(int width, int height,
621
                                PhysicalCoords physical, Integer maxDeadBoards) {
UNCOV
622
                        super(null, physical, null, maxDeadBoards);
×
UNCOV
623
                        this.width = width;
×
UNCOV
624
                        this.height = height;
×
UNCOV
625
                }
×
626

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

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

683
                @Override
684
                <T> T doVisit(CreateVisitor<T> visitor) {
685
                        return visitor.dimensionsAt(this);
3✔
686
                }
687

688
                @Override
689
                public int getArea() {
690
                        return width * height * TRIAD_DEPTH;
3✔
691
                }
692
        }
693

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

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

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

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

745
                @Override
746
                <T> T doVisit(CreateVisitor<T> visitor) {
747
                        return visitor.board(this);
3✔
748
                }
749

750
                @Override
751
                public int getArea() {
752
                        return 1;
3✔
753
                }
754
        }
755

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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