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

SpiNNakerManchester / JavaSpiNNaker / 14556105732

21 Mar 2025 04:17PM UTC coverage: 38.266%. Remained the same
14556105732

push

github

web-flow
Merge pull request #1222 from SpiNNakerManchester/more_spalloc_rest_calls

More spalloc rest calls

70 of 815 new or added lines in 33 files covered. (8.59%)

1689 existing lines in 35 files now uncovered.

9193 of 24024 relevant lines covered (38.27%)

1.15 hits per line

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

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

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

25
import java.io.IOException;
26
import java.time.Duration;
27
import java.time.Instant;
28
import java.util.Collection;
29
import java.util.List;
30
import java.util.Map;
31
import java.util.Objects;
32
import java.util.Optional;
33
import java.util.Set;
34

35
import javax.validation.Valid;
36
import javax.validation.constraints.AssertTrue;
37
import javax.validation.constraints.NotNull;
38
import javax.validation.constraints.Positive;
39
import javax.validation.constraints.PositiveOrZero;
40

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

44
import com.google.errorprone.annotations.Keep;
45
import com.google.errorprone.annotations.MustBeClosed;
46

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1064
                /** @return The name of the machine. Unique. */
1065
                String getName();
1066

1067
                /** @return The tags associated with the machine. */
1068
                Set<String> getTags();
1069

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

1073
                /** @return The height of the machine. */
1074
                int getHeight();
1075

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

1079
                /** @return Whether the machine wraps in the vertical direction. */
1080
                boolean isVerticallyWrapped();
1081

1082
                /** @return Whether this machine is currently in service. */
1083
                boolean isInService();
1084

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

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

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

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

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

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

1145
                /**
1146
                 * @return The IP address of the BMP of the root board of the machine.
1147
                 */
1148
                String getRootBoardBMPAddress();
1149

1150
                /** @return The boards supported by the machine. */
1151
                List<Integer> getBoardNumbers();
1152

1153
                /** @return The IDs of boards currently available to be allocated. */
1154
                List<Integer> getAvailableBoards();
1155

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

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

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

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

1202
                /**
1203
                 * What machine is the board on?
1204
                 *
1205
                 * @return name of machine
1206
                 */
1207
                String getMachine();
1208

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

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

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

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

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

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

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

1251
                /** @return The root Z coordinate of this sub-machine. */
1252
                int getRootZ();
1253

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

1257
                /** @return The height of this sub-machine, in triads. */
1258
                int getHeight();
1259

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

1266
                /** @return The connection details of this sub-machine. */
1267
                List<ConnectionInfo> getConnections();
1268

1269
                /** @return The board locations of this sub-machine. */
1270
                List<BoardCoordinates> getBoards();
1271

1272
                /** @return Whether this sub-machine is switched on. */
1273
                PowerState getPower();
1274

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