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

SpiNNakerManchester / JavaSpiNNaker / 6233274834

19 Sep 2023 08:46AM UTC coverage: 36.409% (-0.6%) from 36.982%
6233274834

Pull #658

github

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

1656 of 1656 new or added lines in 260 files covered. (100.0%)

8373 of 22997 relevant lines covered (36.41%)

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 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 Handle to the job, or {@code empty} if the job couldn't be made.
196
         */
197
        Optional<Job> createJob(@NotNull String owner,
198
                        @Valid CreateDescriptor descriptor, String machineName,
199
                        List<String> tags, Duration keepaliveInterval,
200
                        byte[] originalRequest);
201

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

© 2025 Coveralls, Inc