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

SpiNNakerManchester / JavaSpiNNaker / 6819

17 Jul 2025 10:30AM UTC coverage: 36.227% (-1.3%) from 37.516%
6819

push

github

web-flow
Merge pull request #1257 from SpiNNakerManchester/fix_migration_issues

Fix migration issues

1898 of 5876 branches covered (32.3%)

Branch coverage included in aggregate %.

13 of 16 new or added lines in 2 files covered. (81.25%)

256 existing lines in 12 files now uncovered.

8933 of 24022 relevant lines covered (37.19%)

0.74 hits per line

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

47.1
/SpiNNaker-allocserv/src/main/java/uk/ac/manchester/spinnaker/alloc/SpallocProperties.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;
17

18
import static java.util.Objects.nonNull;
19

20
import java.io.File;
21
import java.time.Duration;
22
import java.util.Set;
23

24
import javax.sql.DataSource;
25
import jakarta.validation.Valid;
26
import jakarta.validation.constraints.AssertTrue;
27
import jakarta.validation.constraints.Email;
28
import jakarta.validation.constraints.Max;
29
import jakarta.validation.constraints.Min;
30
import jakarta.validation.constraints.NotBlank;
31
import jakarta.validation.constraints.NotEmpty;
32
import jakarta.validation.constraints.NotNull;
33
import jakarta.validation.constraints.Positive;
34
import jakarta.validation.constraints.PositiveOrZero;
35

36
import org.springframework.boot.context.properties.ConfigurationProperties;
37
import org.springframework.boot.context.properties.bind.ConstructorBinding;
38
import org.springframework.boot.context.properties.bind.DefaultValue;
39
import org.springframework.core.io.Resource;
40
import org.springframework.security.oauth2.core.AuthorizationGrantType;
41
import org.springframework.validation.annotation.Validated;
42

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

45
import uk.ac.manchester.spinnaker.utils.UsedInJavadocOnly;
46
import uk.ac.manchester.spinnaker.utils.validation.IPAddress;
47
import uk.ac.manchester.spinnaker.utils.validation.TCPPort;
48

49
/**
50
 * Spalloc service management properties. These are all intended to be set via
51
 * the configuration file.
52
 *
53
 * @author Donal Fellows
54
 */
55
@ConfigurationProperties("spalloc")
56
@Validated
57
public class SpallocProperties {
58
        /** Path to the main database file. */
59
        private File databasePath;
60

61
        /** How long should long calls take before returning anyway? */
62
        private Duration wait;
63

64
        /**
65
         * Whether to pause <em>all</em> periodic callbacks. Probably only useful
66
         * for debugging and testing.
67
         */
68
        private boolean pause;
69

70
        /** The main working directory. Referred to by other properties. */
71
        private File workingDirectory;
72

73
        private HistoricalDataProperties historicalData;
74

75
        private KeepaliveProperties keepalive;
76

77
        private AllocatorProperties allocator;
78

79
        private AuthProperties auth;
80

81
        private QuotaProperties quota;
82

83
        private TxrxProperties transceiver;
84

85
        private DBProperties sqlite;
86

87
        private CompatibilityProperties compat;
88

89
        private ProxyProperties proxy;
90

91
        /** Properties relating to board issue reporting. */
92
        private ReportProperties reportEmail;
93

94
        /** Properties relating to control of the overall machine state. */
95
        private StateControlProperties stateCtrl;
96

97
        /** The database connection configuration. */
98
        private DataSourceProperties datasource;
99

100
        /**
101
         * @param databasePath
102
         *            Path to the main database file.
103
         * @param wait
104
         *            How long should long calls take before returning anyway?
105
         * @param pause
106
         *            Whether to pause <em>all</em> periodic callbacks. Probably
107
         *            only useful for debugging and testing.
108
         * @param workingDirectory
109
         *            The main working directory. Referred to by other properties.
110
         * @param allocator
111
         *            Properties relating to the allocation engine.
112
         * @param auth
113
         *            Properties relating to authentication and authorization.
114
         * @param compat
115
         *            Properties relating to the Spalloc v1 compatibility layer.
116
         * @param historicalData
117
         *            Properties relating to historical data management.
118
         * @param keepalive
119
         *            Properties relating to job keep-alive messages.
120
         * @param proxy
121
         *            Properties relating to the SDP proxying.
122
         * @param quota
123
         *            Properties relating to quota management.
124
         * @param sqlite
125
         *            Properties relating to the details of working with SQLite.
126
         * @param reportEmail
127
         *            Properties relating to board issue reporting.
128
         * @param transceiver
129
         *            Properties relating to low-level transceiver control and the
130
         *            BMPs.
131
         * @param stateControl
132
         *            Properties relating to control of the overall machine state.
133
         * @param datasource
134
         *            The database connection configuration.
135
         */
136
        @SuppressWarnings("checkstyle:ParameterNumber")
137
        @ConstructorBinding
138
        public SpallocProperties(//
139
                        @DefaultValue("spalloc.sqlite3") File databasePath,
140
                        @DefaultValue("30s") Duration wait,
141
                        @DefaultValue("false") boolean pause,
142
                        @DefaultValue(".") File workingDirectory,
143
                        @DefaultValue AllocatorProperties allocator,
144
                        @DefaultValue AuthProperties auth,
145
                        @DefaultValue CompatibilityProperties compat,
146
                        @DefaultValue HistoricalDataProperties historicalData,
147
                        @DefaultValue KeepaliveProperties keepalive,
148
                        @DefaultValue ProxyProperties proxy,
149
                        @DefaultValue QuotaProperties quota,
150
                        @DefaultValue DBProperties sqlite,
151
                        @DefaultValue ReportProperties reportEmail,
152
                        @DefaultValue TxrxProperties transceiver,
153
                        @DefaultValue StateControlProperties stateControl,
154
                        @DefaultValue DataSourceProperties datasource) {
2✔
155
                this.databasePath = databasePath;
2✔
156
                this.wait = wait;
2✔
157
                this.pause = pause;
2✔
158
                this.workingDirectory = workingDirectory;
2✔
159
                this.allocator = allocator;
2✔
160
                this.auth = auth;
2✔
161
                this.compat = compat;
2✔
162
                this.historicalData = historicalData;
2✔
163
                this.keepalive = keepalive;
2✔
164
                this.proxy = proxy;
2✔
165
                this.quota = quota;
2✔
166
                this.sqlite = sqlite;
2✔
167
                this.reportEmail = reportEmail;
2✔
168
                this.transceiver = transceiver;
2✔
169
                this.stateCtrl = stateControl;
2✔
170
                this.datasource = datasource;
2✔
171
        }
2✔
172

173
        /**
174
         * Path to the main database file.
175
         *
176
         * @return Path.
177
         */
178
        @NotNull
179
        public File getDatabasePath() {
180
                return databasePath;
2✔
181
        }
182

183
        void setDatabasePath(File databasePath) {
184
                this.databasePath = databasePath;
×
185
        }
×
186

187
        @Keep
188
        @AssertTrue(message = "directory of database path must exist")
189
        private boolean isDatabaseInSaneLocation() {
190
                return databasePath.getAbsoluteFile().getParentFile().exists();
2✔
191
        }
192

193
        /**
194
         * How long should long calls take before returning anyway?
195
         *
196
         * @return Wait time.
197
         */
198
        @NotNull
199
        public Duration getWait() {
200
                return wait;
2✔
201
        }
202

203
        void setWait(Duration wait) {
204
                this.wait = wait;
×
205
        }
×
206

207
        /**
208
         * Whether to pause <em>all</em> periodic callbacks. Probably only useful
209
         * for debugging.
210
         *
211
         * @return Whether to pause periodic callbacks. Note that this property is
212
         *         runtime-settable via the global administration interface, which
213
         *         should be the only place that reads from here directly.
214
         */
215
        public boolean isPause() {
216
                return pause;
2✔
217
        }
218

219
        void setPause(boolean pause) {
220
                this.pause = pause;
×
221
        }
×
222

223
        /**
224
         * The main working directory. Referred to by other properties.
225
         *
226
         * @return Main working directory.
227
         */
228
        @NotNull
229
        public File getWorkingDirectory() {
230
                return workingDirectory;
2✔
231
        }
232

233
        void setWorkingDirectory(File workingDirectory) {
234
                this.workingDirectory = workingDirectory;
×
235
        }
×
236

237
        @Keep
238
        @AssertTrue(message = "working directory must exist")
239
        private boolean isValidWorkingDirectory() {
240
                return workingDirectory.exists() && workingDirectory.isDirectory();
2!
241
        }
242

243
        /**
244
         * @return Properties relating to historical data management.
245
         */
246
        @NotNull
247
        @Valid
248
        public HistoricalDataProperties getHistoricalData() {
249
                return historicalData;
2✔
250
        }
251

252
        void setHistoricalData(HistoricalDataProperties historicalData) {
253
                this.historicalData = historicalData;
×
254
        }
×
255

256
        /**
257
         * @return Properties relating to job keep-alive messages.
258
         */
259
        @NotNull
260
        @Valid
261
        public KeepaliveProperties getKeepalive() {
262
                return keepalive;
2✔
263
        }
264

265
        void setKeepalive(KeepaliveProperties keepalive) {
266
                this.keepalive = keepalive;
×
267
        }
×
268

269
        /**
270
         * @return Properties relating to the allocation engine.
271
         */
272
        @NotNull
273
        @Valid
274
        public AllocatorProperties getAllocator() {
275
                return allocator;
2✔
276
        }
277

278
        void setAllocator(AllocatorProperties allocator) {
279
                this.allocator = allocator;
×
280
        }
×
281

282
        /**
283
         * @return Properties relating to authentication and authorization.
284
         */
285
        @NotNull
286
        @Valid
287
        public AuthProperties getAuth() {
288
                return auth;
2✔
289
        }
290

291
        void setAuth(AuthProperties auth) {
292
                this.auth = auth;
×
293
        }
×
294

295
        /**
296
         * @return Properties relating to the SDP proxying.
297
         */
298
        @NotNull
299
        @Valid
300
        public ProxyProperties getProxy() {
301
                return proxy;
2✔
302
        }
303

304
        void setProxy(ProxyProperties proxy) {
305
                this.proxy = proxy;
×
306
        }
×
307

308
        /**
309
         * @return Properties relating to quota management.
310
         */
311
        @NotNull
312
        @Valid
313
        public QuotaProperties getQuota() {
314
                return quota;
2✔
315
        }
316

317
        void setQuota(QuotaProperties quota) {
318
                this.quota = quota;
×
319
        }
×
320

321
        /**
322
         * @return Properties relating to low-level transceiver control and the
323
         *         BMPs.
324
         */
325
        @NotNull
326
        @Valid
327
        public TxrxProperties getTransceiver() {
328
                return transceiver;
2✔
329
        }
330

331
        void setTransceiver(TxrxProperties transceiver) {
332
                this.transceiver = transceiver;
×
333
        }
×
334

335
        /**
336
         * @return Properties relating to the details of working with SQLite.
337
         */
338
        @NotNull
339
        @Valid
340
        public DBProperties getSqlite() {
341
                return sqlite;
2✔
342
        }
343

344
        void setSqlite(DBProperties sqlite) {
345
                this.sqlite = sqlite;
×
346
        }
×
347

348
        /** @return Properties relating to board issue reporting. */
349
        @NotNull
350
        @Valid
351
        public ReportProperties getReportEmail() {
352
                return reportEmail;
2✔
353
        }
354

355
        void setReportEmail(ReportProperties reportEmail) {
356
                this.reportEmail = reportEmail;
×
357
        }
×
358

359
        /**
360
         * @return Properties relating to the Spalloc v1 compatibility layer.
361
         */
362
        @NotNull
363
        @Valid
364
        public CompatibilityProperties getCompat() {
365
                return compat;
2✔
366
        }
367

368
        void setCompat(CompatibilityProperties compat) {
369
                this.compat = compat;
×
370
        }
×
371

372
        /** @return Properties relating to control of the overall machine state. */
373
        @NotNull
374
        @Valid
375
        public StateControlProperties getStateControl() {
376
                return stateCtrl;
2✔
377
        }
378

379
        void setStateControl(StateControlProperties stateCtrl) {
380
                this.stateCtrl = stateCtrl;
×
381
        }
×
382

383
        /** @return The database connection configuration. */
384
        @NotNull
385
        @Valid
386
        public DataSourceProperties getDatasource() {
387
                return datasource;
2✔
388
        }
389

390
        void setDatasource(DataSourceProperties datasource) {
391
                this.datasource = datasource;
×
392
        }
×
393

394
        /** How to handle job data that is now only of historic interest. */
395
        public static class HistoricalDataProperties {
396
                /**
397
                 * Path to the historical job database file. <em>Must be distinct from
398
                 * the main database!</em>
399
                 */
400
                private File path;
401

402
                /**
403
                 * How long after job completion should we wait before moving the data?
404
                 */
405
                private Duration gracePeriod;
406

407
                /**
408
                 * Cron expression saying when to move completed jobs to the historical
409
                 * database.
410
                 */
411
                private String schedule;
412

413
                /**
414
                 * Database connection properties for the connection to the historical
415
                 * database.
416
                 */
417
                private DataSourceProperties datasource;
418

419
                /**
420
                 * @param path
421
                 *            Path to the historical job database file. <em>Must be
422
                 *            distinct from the main database!</em>
423
                 * @param gracePeriod
424
                 *            How long after job completion should we wait before moving
425
                 *            the data?
426
                 * @param schedule
427
                 *            Cron expression saying when to move completed jobs to the
428
                 *            historical database.
429
                 * @param datasource
430
                 *            Database connection properties for the connection to the
431
                 *            historical database.
432
                 */
433
                @ConstructorBinding
434
                public HistoricalDataProperties(
435
                                @DefaultValue("spalloc-history.sqlite3") File path,
436
                                @DefaultValue("14d") Duration gracePeriod,
437
                                @DefaultValue("0 0 2 * * *") String schedule,
438
                                @DefaultValue DataSourceProperties datasource) {
2✔
439
                        this.path = path;
2✔
440
                        this.gracePeriod = gracePeriod;
2✔
441
                        this.schedule = schedule;
2✔
442
                        this.datasource = datasource;
2✔
443
                }
2✔
444

445
                /**
446
                 * @return Path to the historical job database file. <em>Must be
447
                 *         distinct from the main database!</em>
448
                 */
449
                @NotNull
450
                public File getPath() {
451
                        return path;
2✔
452
                }
453

454
                void setPath(File path) {
455
                        this.path = path;
×
UNCOV
456
                }
×
457

458
                /**
459
                 * @return How long after job completion should we wait before moving
460
                 *         the data?
461
                 */
462
                @NotNull
463
                public Duration getGracePeriod() {
464
                        return gracePeriod;
2✔
465
                }
466

467
                void setGracePeriod(Duration gracePeriod) {
468
                        this.gracePeriod = gracePeriod;
×
UNCOV
469
                }
×
470

471
                /**
472
                 * @return Cron expression saying when to move completed jobs to the
473
                 *         historical database.
474
                 */
475
                @NotBlank
476
                public String getSchedule() {
477
                        return schedule;
2✔
478
                }
479

480
                void setSchedule(String schedule) {
481
                        this.schedule = schedule;
×
UNCOV
482
                }
×
483

484
                /**
485
                 * @return Database connection properties for the connection to the
486
                 *         historical database.
487
                 */
488
                @Valid
489
                public DataSourceProperties getDatasource() {
490
                        return datasource;
2✔
491
                }
492

493
                void setDatasource(DataSourceProperties datasource) {
494
                        this.datasource = datasource;
×
UNCOV
495
                }
×
496
        }
497

498
        /** How to handle keepalive messages. */
499
        public static class KeepaliveProperties {
500
                /**
501
                 * Time between runs of the keepalive-expiry algorithm.
502
                 */
503
                private Duration expiryPeriod;
504

505
                /** Minimum keepalive period. */
506
                private Duration min;
507

508
                /** Maximum keepalive period. */
509
                private Duration max;
510

511
                /**
512
                 * @param expiryPeriod
513
                 *            Time between runs of the keepalive-expiry algorithm.
514
                 * @param min
515
                 *            Minimum keepalive period.
516
                 * @param max
517
                 *            Maximum keepalive period.
518
                 */
519
                @ConstructorBinding
520
                public KeepaliveProperties(//
521
                                @DefaultValue("30s") Duration expiryPeriod,
522
                                @DefaultValue("30s") Duration min,
523
                                @DefaultValue("300s") Duration max) {
2✔
524
                        this.expiryPeriod = expiryPeriod;
2✔
525
                        this.min = min;
2✔
526
                        this.max = max;
2✔
527
                }
2✔
528

529
                /**
530
                 * Time between runs of the keepalive-expiry algorithm.
531
                 *
532
                 * @return Time between runs of the keepalive-expiry algorithm.
533
                 */
534
                @NotNull
535
                public Duration getExpiryPeriod() {
536
                        return expiryPeriod;
2✔
537
                }
538

539
                void setExpiryPeriod(Duration expiryPeriod) {
UNCOV
540
                        this.expiryPeriod = expiryPeriod;
×
UNCOV
541
                }
×
542

543
                /** @return Minimum keepalive period. */
544
                @NotNull
545
                public Duration getMin() {
546
                        return min;
2✔
547
                }
548

549
                void setMin(Duration min) {
UNCOV
550
                        this.min = min;
×
UNCOV
551
                }
×
552

553
                /** @return Maximum keepalive period. */
554
                @NotNull
555
                public Duration getMax() {
556
                        return max;
2✔
557
                }
558

559
                void setMax(Duration max) {
UNCOV
560
                        this.max = max;
×
UNCOV
561
                }
×
562

563
                @Keep
564
                @AssertTrue(message = "max must be more than min")
565
                private boolean isMaxMoreThanMin() {
566
                        return max.compareTo(min) > 0;
2!
567
                }
568
        }
569

570
        /** Configuration of the main resource allocation engine. */
571
        public static class AllocatorProperties {
572
                /**
573
                 * Time between runs of the main allocation algorithm.
574
                 */
575
                private Duration period;
576

577
                /**
578
                 * Maximum span of job importance that will be allocated at once.
579
                 * Priority is the rate at which importance is accrued.
580
                 */
581
                private int importanceSpan;
582

583
                /** Properties relating to job priority scaling. */
584
                private PriorityScale priorityScale;
585

586
                /**
587
                 * Number of reports of board problems at which the board is taken out
588
                 * of service.
589
                 */
590
                private int reportActionThreshold;
591

592
                /** Name of user that system-generated reports are done by. */
593
                private String systemReportUser;
594

595
                /** Command code to accept for an emergency shutdown. */
596
                private String emergencyStopCommandCode;
597

598
                /**
599
                 * @param period
600
                 *            Time between runs of the main allocation algorithm.
601
                 * @param importanceSpan
602
                 *            Maximum span of job importance that will be allocated at
603
                 *            once. Priority is the rate at which importance is accrued.
604
                 * @param priorityScale
605
                 *            Properties relating to job priority scaling.
606
                 * @param reportActionThreshold
607
                 *            Number of reports of board problems at which the board is
608
                 *            taken out of service.
609
                 * @param systemReportUser
610
                 *            Name of user that system-generated reports are done by.
611
                 * @param emergencyStopCommandCode
612
                 *           Command code to accept for an emergency stop.
613
                 */
614
                @ConstructorBinding
615
                public AllocatorProperties(@DefaultValue("5s") Duration period,
616
                                @DefaultValue("10000") int importanceSpan,
617
                                @DefaultValue PriorityScale priorityScale,
618
                                @DefaultValue("2") int reportActionThreshold,
619
                                @DefaultValue("") String systemReportUser,
620
                                @DefaultValue String emergencyStopCommandCode) {
2✔
621
                        this.period = period;
2✔
622
                        this.importanceSpan = importanceSpan;
2✔
623
                        this.priorityScale = priorityScale;
2✔
624
                        this.reportActionThreshold = reportActionThreshold;
2✔
625
                        this.systemReportUser = systemReportUser;
2✔
626
                        this.emergencyStopCommandCode = emergencyStopCommandCode;
2✔
627
                }
2✔
628

629
                /**
630
                 * Time between runs of the main allocation algorithm.
631
                 *
632
                 * @return Time between runs of the main allocation algorithm.
633
                 */
634
                @NotNull
635
                public Duration getPeriod() {
636
                        return period;
2✔
637
                }
638

639
                void setPeriod(Duration period) {
UNCOV
640
                        this.period = period;
×
UNCOV
641
                }
×
642

643
                /**
644
                 * Maximum span of job importance that will be allocated at once.
645
                 * Priority is the rate at which importance is accrued.
646
                 *
647
                 * @return Maximum importance span for considered jobs for a particular
648
                 *         run of the allocator algorithm.
649
                 */
650
                @Positive
651
                public int getImportanceSpan() {
652
                        return importanceSpan;
2✔
653
                }
654

655
                void setImportanceSpan(int importanceSpan) {
UNCOV
656
                        this.importanceSpan = importanceSpan;
×
UNCOV
657
                }
×
658

659
                /**
660
                 * Properties relating to job priority scaling.
661
                 *
662
                 * @return Properties relating to job priority scaling.
663
                 */
664
                @NotNull
665
                @Valid
666
                public PriorityScale getPriorityScale() {
667
                        return priorityScale;
2✔
668
                }
669

670
                void setPriorityScale(PriorityScale priorityScale) {
UNCOV
671
                        this.priorityScale = priorityScale;
×
UNCOV
672
                }
×
673

674
                /**
675
                 * @return Number of reports of board problems at which the board is
676
                 *         taken out of service.
677
                 */
678
                @Positive
679
                public int getReportActionThreshold() {
680
                        return reportActionThreshold;
2✔
681
                }
682

683
                void setReportActionThreshold(int threshold) {
UNCOV
684
                        reportActionThreshold = threshold;
×
UNCOV
685
                }
×
686

687
                /** @return Name of user that system-generated reports are done by. */
688
                @NotNull
689
                public String getSystemReportUser() {
690
                        return systemReportUser;
2✔
691
                }
692

693
                void setSystemReportUser(String systemReportUser) {
UNCOV
694
                        this.systemReportUser = systemReportUser;
×
UNCOV
695
                }
×
696

697
                /**
698
                 * @return Command code to accept for an emergency stop.
699
                 */
700
                @NotBlank
701
                public String getEmergencyStopCommandCode() {
702
                        return emergencyStopCommandCode;
2✔
703
                }
704

705
                void setEmergencyStopCommandCode(String emergencyStopCommandCode) {
UNCOV
706
                        this.emergencyStopCommandCode = emergencyStopCommandCode;
×
UNCOV
707
                }
×
708
        }
709

710
        /**
711
         * Priority is the rate at which importance is accrued. Importance is
712
         * determines the order in which jobs are allocated.
713
         */
714
        public static class PriorityScale {
715
                /** Priority scaling factor for jobs given by number of boards. */
716
                private double size;
717

718
                /** Priority scaling factor for jobs given by rectangular dimensions. */
719
                private double dimensions;
720

721
                /** Priority scaling factor for jobs requiring a specific board. */
722
                private double specificBoard;
723

724
                /**
725
                 * @param size
726
                 *            Priority scaling factor for jobs given by number of
727
                 *            boards.
728
                 * @param dimensions
729
                 *            Priority scaling factor for jobs given by rectangular
730
                 *            dimensions.
731
                 * @param specificBoard
732
                 *            Priority scaling factor for jobs requiring a specific
733
                 *            board.
734
                 */
735
                @ConstructorBinding
736
                public PriorityScale(@DefaultValue("1.0") double size,
737
                                @DefaultValue("1.5") double dimensions,
738
                                @DefaultValue("65.0") double specificBoard) {
2✔
739
                        this.size = size;
2✔
740
                        this.dimensions = dimensions;
2✔
741
                        this.specificBoard = specificBoard;
2✔
742
                }
2✔
743

744
                /**
745
                 * @return Priority scaling factor for jobs given by number of boards.
746
                 */
747
                @Positive
748
                public double getSize() {
749
                        return size;
2✔
750
                }
751

752
                void setSize(double factor) {
UNCOV
753
                        size = factor;
×
UNCOV
754
                }
×
755

756
                /**
757
                 * @return Priority scaling factor for jobs given by rectangular
758
                 *         dimensions.
759
                 */
760
                @Positive
761
                public double getDimensions() {
762
                        return dimensions;
2✔
763
                }
764

765
                void setDimensions(double factor) {
UNCOV
766
                        dimensions = factor;
×
UNCOV
767
                }
×
768

769
                /**
770
                 * @return Priority scaling factor for jobs requiring a specific board.
771
                 */
772
                @Positive
773
                public double getSpecificBoard() {
774
                        return specificBoard;
2✔
775
                }
776

777
                void setSpecificBoard(double factor) {
UNCOV
778
                        specificBoard = factor;
×
UNCOV
779
                }
×
780
        }
781

782
        /** Notify an administrator about problems reported with boards. */
783
        public static class ReportProperties {
784
                private static final String DEFAULT_SUBJECT =
785
                                "NOTICE: Board taken out of service";
786

787
                /** Whether to send an email about reported boards. */
788
                private boolean send;
789

790
                /** The {@code From:} email address. */
791
                private String from;
792

793
                /** The {@code To:} email address. */
794
                private String to;
795

796
                /** The {@code Subject:} header. */
797
                private String subject;
798

799
                /**
800
                 * @param send
801
                 *            Whether to send an email about reported boards.
802
                 * @param from
803
                 *            The {@code From:} email address.
804
                 * @param to
805
                 *            The {@code To:} email address.
806
                 * @param subject
807
                 *            The {@code Subject:} header.
808
                 */
809
                @ConstructorBinding
810
                public ReportProperties(@DefaultValue("false") boolean send,
811
                                @DefaultValue("spalloc@localhost") String from,
812
                                @DefaultValue("root@localhost") String to,
813
                                @DefaultValue(DEFAULT_SUBJECT) String subject) {
2✔
814
                        this.send = send;
2✔
815
                        this.from = from;
2✔
816
                        this.to = to;
2✔
817
                        this.subject = subject;
2✔
818
                }
2✔
819

820
                /** @return Whether to send an email about reported boards. */
821
                public boolean isSend() {
822
                        return send;
2✔
823
                }
824

825
                void setSend(boolean send) {
UNCOV
826
                        this.send = send;
×
UNCOV
827
                }
×
828

829
                /** @return The {@code From:} email address. */
830
                @Email
831
                public String getFrom() {
832
                        return from;
2✔
833
                }
834

835
                void setFrom(String address) {
UNCOV
836
                        from = address;
×
UNCOV
837
                }
×
838

839
                /** @return The {@code To:} email address. */
840
                @Email
841
                public String getTo() {
842
                        return to;
2✔
843
                }
844

845
                void setTo(String address) {
UNCOV
846
                        to = address;
×
UNCOV
847
                }
×
848

849
                /** @return The {@code Subject:} header. */
850
                @NotBlank
851
                public String getSubject() {
852
                        return subject;
2✔
853
                }
854

855
                void setSubject(String subject) {
UNCOV
856
                        this.subject = subject;
×
UNCOV
857
                }
×
858

859
                @Keep
860
                @AssertTrue(
861
                                message = "must supply from, to, and subject if send enabled")
862
                private boolean fieldsIfEnabled() {
UNCOV
863
                        return !send || (nonNull(from) && nonNull(to) && nonNull(subject));
×
864
                }
865
        }
866

867
        /** Authentication and authorization configuration. */
868
        public static class AuthProperties {
869
                /**
870
                 * Whether to enable HTTP BASIC authentication. Useful for simple
871
                 * clients.
872
                 */
873
                private boolean basic;
874

875
                /**
876
                 * The authentication realm. Must not contain quote characters!
877
                 */
878
                private String realm;
879

880
                /**
881
                 * Whether to enable HTTP form+session authentication. Much faster than
882
                 * BASIC, but requires a more complex client. You must enable this if
883
                 * you are supporting the Web UI.
884
                 */
885
                private boolean localForm;
886

887
                /**
888
                 * Force a known local admin user to exist with a known (by default)
889
                 * password.
890
                 */
891
                private boolean addDummyUser;
892

893
                /**
894
                 * Whether to generate a random password for the above user. If so, the
895
                 * password will be written to the log.
896
                 */
897
                private boolean dummyRandomPass;
898

899
                /**
900
                 * The name of the system default group. Only made if the
901
                 * {@linkplain #addDummyUser dummy user} is made.
902
                 */
903
                private String systemGroup;
904

905
                /** Provide extra information to callers on auth failures. */
906
                private boolean debugFailures;
907

908
                /** Number of login failures before automatic lock-out. */
909
                private int maxLoginFailures;
910

911
                /** Length of time that automatic lock-out lasts. */
912
                private Duration accountLockDuration;
913

914
                /**
915
                 * How often do we look for users to end their lock-out?
916
                 */
917
                private Duration unlockPeriod;
918

919
                /**
920
                 * OpenID-related security properties. Required for allowing people to
921
                 * use HBP/EBRAINS identities.
922
                 */
923
                private OpenIDProperties openid;
924

925
                /**
926
                 * @param basic
927
                 *            Whether to enable HTTP BASIC authentication. Useful for
928
                 *            simple clients.
929
                 * @param realm
930
                 *            The authentication realm. Must not contain quote
931
                 *            characters!
932
                 * @param localForm
933
                 *            Whether to enable HTTP form+session authentication. Much
934
                 *            faster than BASIC, but requires a more complex client. You
935
                 *            must enable this if you are supporting the Web UI.
936
                 * @param addDummyUser
937
                 *            Force a known local admin user to exist with a known (by
938
                 *            default) password.
939
                 * @param dummyRandomPass
940
                 *            Whether to generate a random password for the above user.
941
                 *            If so, the password will be written to the log.
942
                 * @param systemGroup
943
                 *            The name of the system default group. Only made if the
944
                 *            dummy user is made.
945
                 * @param debugFailures
946
                 *            Provide extra information to callers on auth failures.
947
                 * @param maxLoginFailures
948
                 *            Number of login failures before automatic lock-out.
949
                 * @param accountLockDuration
950
                 *            Length of time that automatic lock-out lasts.
951
                 * @param unlockPeriod
952
                 *            How often do we look for users to end their lock-out?
953
                 * @param openid
954
                 *            OpenID-related security properties. Required for allowing
955
                 *            people to use HBP/EBRAINS identities.
956
                 */
957
                @ConstructorBinding
958
                public AuthProperties(//
959
                                @DefaultValue("true") boolean basic,
960
                                @DefaultValue("SpallocService") String realm,
961
                                @DefaultValue("true") boolean localForm,
962
                                @DefaultValue("false") boolean addDummyUser,
963
                                @DefaultValue("true") boolean dummyRandomPass,
964
                                @DefaultValue("wheel") String systemGroup,
965
                                @DefaultValue("false") boolean debugFailures,
966
                                @DefaultValue("3") int maxLoginFailures,
967
                                @DefaultValue("24h") Duration accountLockDuration,
968
                                @DefaultValue("60s") Duration unlockPeriod,
969
                                @DefaultValue OpenIDProperties openid) {
2✔
970
                        this.basic = basic;
2✔
971
                        this.realm = realm;
2✔
972
                        this.localForm = localForm;
2✔
973
                        this.addDummyUser = addDummyUser;
2✔
974
                        this.dummyRandomPass = dummyRandomPass;
2✔
975
                        this.systemGroup = systemGroup;
2✔
976
                        this.debugFailures = debugFailures;
2✔
977
                        this.maxLoginFailures = maxLoginFailures;
2✔
978
                        this.accountLockDuration = accountLockDuration;
2✔
979
                        this.unlockPeriod = unlockPeriod;
2✔
980
                        this.setOpenid(openid);
2✔
981
                }
2✔
982

983
                /**
984
                 * Whether to enable HTTP BASIC authentication. Useful for simple
985
                 * clients; not great with browsers.
986
                 *
987
                 * @return Whether to enable HTTP BASIC authentication.
988
                 */
989
                public boolean isBasic() {
990
                        return basic;
2✔
991
                }
992

993
                void setBasic(boolean basic) {
UNCOV
994
                        this.basic = basic;
×
UNCOV
995
                }
×
996

997
                /**
998
                 * The authentication realm. Must not contain quote characters!
999
                 *
1000
                 * @return the realm.
1001
                 */
1002
                @NotNull
1003
                public String getRealm() {
1004
                        return realm;
2✔
1005
                }
1006

1007
                void setRealm(String realm) {
UNCOV
1008
                        this.realm = realm;
×
UNCOV
1009
                }
×
1010

1011
                /**
1012
                 * Whether to enable HTTP form+session authentication. Much faster than
1013
                 * BASIC, but requires a more complex client. You must enable this if
1014
                 * you are supporting the Web UI.
1015
                 *
1016
                 * @return Whether to enable HTTP form+session authentication.
1017
                 */
1018
                public boolean isLocalForm() {
1019
                        return localForm;
2✔
1020
                }
1021

1022
                void setLocalForm(boolean localForm) {
UNCOV
1023
                        this.localForm = localForm;
×
UNCOV
1024
                }
×
1025

1026
                /**
1027
                 * @return Force a known local admin user to exist with a known
1028
                 *         password.
1029
                 */
1030
                public boolean isAddDummyUser() {
1031
                        return addDummyUser;
2✔
1032
                }
1033

1034
                void setAddDummyUser(boolean addDummyUser) {
UNCOV
1035
                        this.addDummyUser = addDummyUser;
×
UNCOV
1036
                }
×
1037

1038
                /**
1039
                 * Whether to generate a random password for the default admin user. If
1040
                 * so, the password will be written to the log.
1041
                 *
1042
                 * @return Whether to generate a random password for the default admin
1043
                 *         user.
1044
                 */
1045
                public boolean isDummyRandomPass() {
UNCOV
1046
                        return dummyRandomPass;
×
1047
                }
1048

1049
                void setDummyRandomPass(boolean dummyRandomPass) {
UNCOV
1050
                        this.dummyRandomPass = dummyRandomPass;
×
UNCOV
1051
                }
×
1052

1053
                /**
1054
                 * The name of the system default group, that is internal and has no
1055
                 * quota (initially). Only made if the {@linkplain #addDummyUser dummy
1056
                 * user} is made.
1057
                 *
1058
                 * @return the name of the system group
1059
                 */
1060
                public String getSystemGroup() {
1061
                        return systemGroup;
2✔
1062
                }
1063

1064
                void setSystemGroup(String systemGroup) {
UNCOV
1065
                        this.systemGroup = systemGroup;
×
UNCOV
1066
                }
×
1067

1068
                /** @return Provide extra information to callers on auth failures. */
1069
                public boolean isDebugFailures() {
UNCOV
1070
                        return debugFailures;
×
1071
                }
1072

1073
                void setDebugFailures(boolean debugFailures) {
UNCOV
1074
                        this.debugFailures = debugFailures;
×
UNCOV
1075
                }
×
1076

1077
                /** @return Number of login failures before automatic lock-out. */
1078
                @Positive
1079
                public int getMaxLoginFailures() {
1080
                        return maxLoginFailures;
2✔
1081
                }
1082

1083
                void setMaxLoginFailures(int maxLoginFailures) {
UNCOV
1084
                        this.maxLoginFailures = maxLoginFailures;
×
UNCOV
1085
                }
×
1086

1087
                /** @return Length of time that automatic lock-out lasts. */
1088
                @NotNull
1089
                public Duration getAccountLockDuration() {
1090
                        return accountLockDuration;
2✔
1091
                }
1092

1093
                void setAccountLockDuration(Duration accountLockDuration) {
UNCOV
1094
                        this.accountLockDuration = accountLockDuration;
×
UNCOV
1095
                }
×
1096

1097
                /**
1098
                 * How often do we look for users to end their lock-out?
1099
                 *
1100
                 * @return How often do we look for users to end their lock-out?
1101
                 */
1102
                @NotNull
1103
                public Duration getUnlockPeriod() {
1104
                        return unlockPeriod;
2✔
1105
                }
1106

1107
                void setUnlockPeriod(Duration unlockPeriod) {
UNCOV
1108
                        this.unlockPeriod = unlockPeriod;
×
UNCOV
1109
                }
×
1110

1111
                /**
1112
                 * OpenID-related security properties. Required for allowing people to
1113
                 * use HBP/EBRAINS identities.
1114
                 *
1115
                 * @return OpenID-related security properties.
1116
                 */
1117
                @NotNull
1118
                @Valid
1119
                public OpenIDProperties getOpenid() {
1120
                        return openid;
2✔
1121
                }
1122

1123
                void setOpenid(OpenIDProperties openid) {
1124
                        this.openid = openid;
2✔
1125
                }
2✔
1126
        }
1127

1128
        /**
1129
         * OpenID-related security properties. Required for allowing people to use
1130
         * HBP/EBRAINS identities.
1131
         */
1132
        public static class OpenIDProperties {
1133
                /**
1134
                 * Whether to enable OIDC authentication. Required for allowing people
1135
                 * to use HBP/EBRAINS identities.
1136
                 */
1137
                private boolean enable;
1138

1139
                /**
1140
                 * The scopes desired. Referred to elsewhere in the configuration file.
1141
                 */
1142
                private Set<String> scopes;
1143

1144
                /** The ID of the registration of the client. */
1145
                private String registrationId;
1146

1147
                /**
1148
                 * The application installation identity. Required for allowing people
1149
                 * to use HBP/EBRAINS identities.
1150
                 */
1151
                private String id;
1152

1153
                /**
1154
                 * The application installation secret. Required for allowing people to
1155
                 * use HBP/EBRAINS identities.
1156
                 */
1157
                private String secret;
1158

1159
                /** Location of the OpenID Opaque Token Introspection service. */
1160
                private String introspection;
1161

1162
                /** Location of the OpenID User Info service. */
1163
                private String userinfo;
1164

1165
                /** Location of the authorization end-point. */
1166
                private String auth;
1167

1168
                /** Location of the token end-point. */
1169
                private String token;
1170

1171
                /** Location of the JWKS. */
1172
                private String jwkSet;
1173

1174
                /** Location of the issuer. */
1175
                private String issuer;
1176

1177
                /** Location of the redirect. */
1178
                private String redirect;
1179

1180
                private AuthorizationGrantType authGrantType;
1181

1182
                /** Prefix for user names originating from OpenID auto-registration. */
1183
                private String usernamePrefix;
1184

1185
                /** What kind of truststore is it. */
1186
                private String truststoreType;
1187

1188
                /** Where the truststore is. */
1189
                private Resource truststorePath;
1190

1191
                /** How to unlock the truststore. */
1192
                private String truststorePassword;
1193

1194
                /**
1195
                 * @param enable
1196
                 *            Whether to enable OIDC authentication. Required for
1197
                 *            allowing people to use HBP/EBRAINS identities.
1198
                 * @param scopes
1199
                 *            The scopes desired. Referred to elsewhere in the
1200
                 *            configuration file.
1201
                 * @param registrationId
1202
                 *            The ID of the registration of the client.
1203
                 * @param id
1204
                 *            The application installation identity. Required for
1205
                 *            allowing people to use HBP/EBRAINS identities.
1206
                 * @param secret
1207
                 *            The application installation secret. Required for allowing
1208
                 *            people to use HBP/EBRAINS identities.
1209
                 * @param introspection
1210
                 *            Location of the OpenID Opaque Token Introspection service.
1211
                 *            Resolved with respect to {@code domain} (if that is given
1212
                 *            and non-empty).
1213
                 * @param userinfo
1214
                 *            Location of the OpenID User Info service. Resolved with
1215
                 *            respect to {@code domain} (if that is given and
1216
                 *            non-empty).
1217
                 * @param auth
1218
                 *            Location of the OpenID Authentication service.
1219
                 * @param authGrantType
1220
                 *            The OpenID authorization grant type.
1221
                 * @param token
1222
                 *            Location of the OpenID token service.
1223
                 * @param jwkSet
1224
                 *            Location of the OpenID JWK Set service.
1225
                 * @param issuer
1226
                 *            Location of the OpenID issuer service.
1227
                 * @param redirect
1228
                 *            Location to redirect users back to after authentication.
1229
                 * @param usernamePrefix
1230
                 *            Prefix for user names originating from OpenID
1231
                 *            auto-registration.
1232
                 * @param truststoreType
1233
                 *            What kind of truststore is it.
1234
                 * @param truststorePath
1235
                 *            Where the truststore is.
1236
                 * @param truststorePassword
1237
                 *            How to unlock the truststore.
1238
                 */
1239
                @SuppressWarnings("checkstyle:ParameterNumber")
1240
                @ConstructorBinding
1241
                public OpenIDProperties(@DefaultValue("false") boolean enable,
1242
                                Set<String> scopes,
1243
                                @DefaultValue("") String registrationId,
1244
                                @DefaultValue("") String id,
1245
                                @DefaultValue("") String secret,
1246
                                @DefaultValue("/") String introspection,
1247
                                @DefaultValue("/") String userinfo,
1248
                                @DefaultValue("/") String auth,
1249
                                @DefaultValue("") String authGrantType,
1250
                                @DefaultValue("/") String token,
1251
                                @DefaultValue("/") String jwkSet,
1252
                                @DefaultValue("/") String issuer,
1253
                                @DefaultValue("/") String redirect,
1254
                                @DefaultValue("openid.") String usernamePrefix,
1255
                                @DefaultValue("PKCS12") String truststoreType,
1256
                                @DefaultValue("classpath:/truststore.p12")
1257
                                Resource truststorePath,
1258
                                @DefaultValue("") String truststorePassword) {
2✔
1259
                        this.enable = enable;
2✔
1260
                        this.setScopes(scopes != null ? scopes : Set.of());
2!
1261
                        this.registrationId = registrationId;
2✔
1262
                        this.id = id;
2✔
1263
                        this.secret = secret;
2✔
1264
                        this.introspection = introspection;
2✔
1265
                        this.userinfo = userinfo;
2✔
1266
                        this.auth = auth;
2✔
1267
                        this.authGrantType = new AuthorizationGrantType(authGrantType);
2✔
1268
                        this.token = token;
2✔
1269
                        this.jwkSet = jwkSet;
2✔
1270
                        this.issuer = issuer;
2✔
1271
                        this.redirect = redirect;
2✔
1272
                        this.usernamePrefix = usernamePrefix;
2✔
1273
                        this.truststoreType = truststoreType;
2✔
1274
                        this.truststorePath = truststorePath;
2✔
1275
                        this.truststorePassword = truststorePassword;
2✔
1276
                }
2✔
1277

1278
                /**
1279
                 * Whether to enable OIDC authentication. Required for allowing people
1280
                 * to use HBP/EBRAINS identities.
1281
                 *
1282
                 * @return Whether to enable OIDC authentication.
1283
                 */
1284
                public boolean isEnable() {
1285
                        return enable;
2✔
1286
                }
1287

1288
                void setEnable(boolean enable) {
UNCOV
1289
                        this.enable = enable;
×
1290
                }
×
1291

1292
                /**
1293
                 * The registration ID of the client.
1294
                 * @return The registration ID.
1295
                 */
1296
                public String getRegistrationId() {
UNCOV
1297
                        return registrationId;
×
1298
                }
1299

1300
                /**
1301
                 * The application installation identity. Required for allowing people
1302
                 * to use HBP/EBRAINS identities.
1303
                 *
1304
                 * @return The application installation identity.
1305
                 */
1306
                public String getId() {
UNCOV
1307
                        return id == null ? null : id.strip();
×
1308
                }
1309

1310
                void setId(String id) {
UNCOV
1311
                        this.id = id;
×
UNCOV
1312
                }
×
1313

1314
                /**
1315
                 * The application installation secret. Required for allowing people to
1316
                 * use HBP/EBRAINS identities.
1317
                 *
1318
                 * @return The application installation secret.
1319
                 */
1320
                public String getSecret() {
UNCOV
1321
                        return secret == null ? null : secret.strip();
×
1322
                }
1323

1324
                void setSecret(String secret) {
UNCOV
1325
                        this.secret = secret;
×
UNCOV
1326
                }
×
1327

1328
                /**
1329
                 * Location of the OpenID Opaque Token Introspection service.
1330
                 *
1331
                 * @return The Introspection location.
1332
                 */
1333
                public String getIntrospection() {
UNCOV
1334
                        return introspection;
×
1335
                }
1336

1337
                /**
1338
                 * Location of the OpenID User Information service.
1339
                 *
1340
                 * @return The Userinfo location.
1341
                 */
1342
                public String getUserinfo() {
UNCOV
1343
                        return userinfo;
×
1344
                }
1345

1346
                /**
1347
                 * Prefix for user names originating from OpenID auto-registration. Not
1348
                 * a good idea to modify this frequently!
1349
                 *
1350
                 * @return Prefix for user names originating from OpenID
1351
                 *         auto-registration.
1352
                 */
1353
                @NotNull
1354
                public String getUsernamePrefix() {
1355
                        return usernamePrefix;
2✔
1356
                }
1357

1358
                void setUsernamePrefix(String usernamePrefix) {
UNCOV
1359
                        this.usernamePrefix = usernamePrefix;
×
UNCOV
1360
                }
×
1361

1362
                /**
1363
                 * The scopes desired. Referred to elsewhere in the configuration file.
1364
                 *
1365
                 * @return The OpenID scopes.
1366
                 */
1367
                @NotEmpty
1368
                public Set<String> getScopes() {
1369
                        return scopes;
2✔
1370
                }
1371

1372
                void setScopes(Set<String> scopes) {
1373
                        this.scopes = scopes;
2✔
1374
                }
2✔
1375

1376
                /**
1377
                 * What kind of truststore is it.
1378
                 *
1379
                 * @return truststore type (default: {@code PKCS12})
1380
                 */
1381
                @NotNull
1382
                public String getTruststoreType() {
1383
                        return truststoreType;
2✔
1384
                }
1385

1386
                void setTruststoreType(String truststoreType) {
UNCOV
1387
                        this.truststoreType = truststoreType;
×
UNCOV
1388
                }
×
1389

1390
                /**
1391
                 * Where the truststore is.
1392
                 *
1393
                 * @return truststore location
1394
                 */
1395
                @NotNull
1396
                public Resource getTruststorePath() {
1397
                        return truststorePath;
2✔
1398
                }
1399

1400
                void setTruststorePath(Resource truststorePath) {
UNCOV
1401
                        this.truststorePath = truststorePath;
×
UNCOV
1402
                }
×
1403

1404
                /**
1405
                 * How to unlock the truststore. This is not considered to be actually
1406
                 * secret, but rather just a technical requirement of the truststore
1407
                 * format.
1408
                 *
1409
                 * @return password for truststore
1410
                 */
1411
                @NotNull
1412
                public String getTruststorePassword() {
1413
                        return truststorePassword;
2✔
1414
                }
1415

1416
                void setTruststorePassword(String truststorePassword) {
1417
                        this.truststorePassword = truststorePassword;
×
UNCOV
1418
                }
×
1419

1420
                /**
1421
                 * @return the OIDC Authorization End-point URL.
1422
                 */
1423
                public String getAuth() {
UNCOV
1424
                        return auth;
×
1425
                }
1426

1427
                void setAuth(String auth) {
1428
                        this.auth = auth;
×
UNCOV
1429
                }
×
1430

1431
                /**
1432
                 * @return the OIDC Token End-point URL.
1433
                 */
1434
                public String getToken() {
UNCOV
1435
                        return token;
×
1436
                }
1437

1438
                void setToken(String token) {
1439
                        this.token = token;
×
UNCOV
1440
                }
×
1441

1442
                /**
1443
                 * @return the OIDC JWK Set URL.
1444
                 */
1445
                public String getJwkSet() {
UNCOV
1446
                        return jwkSet;
×
1447
                }
1448

1449
                void setJwkSet(String jwkSet) {
1450
                        this.jwkSet = jwkSet;
×
UNCOV
1451
                }
×
1452

1453
                /**
1454
                 * @return The OIDC issuer URL.
1455
                 */
1456
                public String getIssuer() {
UNCOV
1457
                        return issuer;
×
1458
                }
1459

1460
                void setIssuer(String issuer) {
1461
                        this.issuer = issuer;
×
UNCOV
1462
                }
×
1463

1464
                /**
1465
                 * @return the redirect URL to return to.
1466
                 */
1467
                public String getRedirect() {
UNCOV
1468
                        return redirect;
×
1469
                }
1470

1471
                void setRedirect(String redirect) {
1472
                        this.redirect = redirect;
×
UNCOV
1473
                }
×
1474

1475
                /**
1476
                 * @return the OIDC Authorization grant type.
1477
                 */
1478
                public AuthorizationGrantType getAuthGrantType() {
UNCOV
1479
                        return authGrantType;
×
1480
                }
1481

1482
                void setAuthGrantType(AuthorizationGrantType authGrantType) {
1483
                        this.authGrantType = authGrantType;
×
1484
                }
×
1485

1486
                /**
1487
                 * @param introspection the OIDC introspection URL.
1488
                 */
1489
                void setIntrospection(String introspection) {
1490
                        this.introspection = introspection;
×
1491
                }
×
1492

1493
                /**
1494
                 * @param userinfo the OIDC user info URL.
1495
                 */
1496
                void setUserinfo(String userinfo) {
UNCOV
1497
                        this.userinfo = userinfo;
×
UNCOV
1498
                }
×
1499

1500
                @Keep
1501
                @AssertTrue(
1502
                                message = "id and secret must be given if OpenID is enabled")
1503
                private boolean isValid() {
1504
                        return !enable || (nonNull(id) && !id.isBlank()
2!
1505
                                        && nonNull(secret) && !secret.isBlank());
2!
1506
                }
1507
        }
1508

1509
        /** Quota management. */
1510
        public static class QuotaProperties {
1511
                /** Default user quota in board-seconds. */
1512
                private int defaultQuota;
1513

1514
                /**
1515
                 * Default quota for organisations inflated from OpenID, in
1516
                 * board-seconds.
1517
                 */
1518
                private long orgQuota;
1519

1520
                /**
1521
                 * Default quota for collabratories inflated from OpenID, in
1522
                 * board-seconds.
1523
                 */
1524
                private long collabQuota;
1525

1526
                /**
1527
                 * Cron expression that says when we consolidate job quotas into the
1528
                 * main quota table.
1529
                 */
1530
                private String consolidationSchedule;
1531

1532
                /**
1533
                 * The URL of the NMPI service which maintains quotas.
1534
                 */
1535
                private String nmpiUrl;
1536

1537
                /**
1538
                 * The API Key to use to access the NMPI service.
1539
                 */
1540
                private String nmpiApiKey;
1541

1542
                /**
1543
                 * The name of the platform to use to read quota.
1544
                 */
1545
                private String nmpiPlatform;
1546

1547
                /**
1548
                 * @param defaultQuota
1549
                 *            Default user quota in board-seconds.
1550
                 * @param defaultOrgQuota
1551
                 *            Default quota for organisations inflated from OpenID, in
1552
                 *            board-seconds.
1553
                 * @param defaultCollabQuota
1554
                 *            Default quota for collabratories inflated from OpenID, in
1555
                 *            board-seconds.
1556
                 * @param consolidationSchedule
1557
                 *            Cron expression that says when we consolidate job quotas
1558
                 *            into the main quota table.
1559
                 * @param nmpiUrl
1560
                 *            The NMPI service URL to communicate with for quotas.
1561
                 * @param nmpiApiKey
1562
                 *            The API key to use to authenticate with the NMPI service.
1563
                 * @param nmpiPlatform
1564
                 *            The platform to use when creating session on the NMPI
1565
                 *            service.
1566
                 */
1567
                @ConstructorBinding
1568
                public QuotaProperties(@DefaultValue("100") int defaultQuota,
1569
                                @DefaultValue("0") long defaultOrgQuota,
1570
                                @DefaultValue("3600000") long defaultCollabQuota,
1571
                                @DefaultValue("0 0 * * * *") String consolidationSchedule,
1572
                                @DefaultValue("") String nmpiUrl,
1573
                                @DefaultValue("") String nmpiApiKey,
1574
                                @DefaultValue("SpiNNaker") String nmpiPlatform) {
2✔
1575
                        this.defaultQuota = defaultQuota;
2✔
1576
                        this.orgQuota = defaultOrgQuota;
2✔
1577
                        this.collabQuota = defaultCollabQuota;
2✔
1578
                        this.consolidationSchedule = consolidationSchedule;
2✔
1579
                        this.nmpiUrl = nmpiUrl;
2✔
1580
                        this.nmpiApiKey = nmpiApiKey;
2✔
1581
                        this.nmpiPlatform = nmpiPlatform;
2✔
1582
                }
2✔
1583

1584
                /**
1585
                 * Default user quota in board-seconds.
1586
                 *
1587
                 * @return Default user quota in board-seconds.
1588
                 */
1589
                @PositiveOrZero
1590
                public int getDefaultQuota() {
1591
                        return defaultQuota;
2✔
1592
                }
1593

1594
                void setDefaultQuota(int defaultQuota) {
UNCOV
1595
                        this.defaultQuota = defaultQuota;
×
UNCOV
1596
                }
×
1597

1598
                /**
1599
                 * Default quota for organisations.
1600
                 *
1601
                 * @return Default quota for organisations inflated from OpenID, in
1602
                 *         board-seconds.
1603
                 */
1604
                public long getDefaultOrgQuota() {
UNCOV
1605
                        return orgQuota;
×
1606
                }
1607

1608
                void setDefaultOrgQuota(long orgQuota) {
UNCOV
1609
                        this.orgQuota = orgQuota;
×
UNCOV
1610
                }
×
1611

1612
                /**
1613
                 * Default quota for collabratories.
1614
                 *
1615
                 * @return Default quota for collabratories inflated from OpenID, in
1616
                 *         board-seconds.
1617
                 */
1618
                public long getDefaultCollabQuota() {
UNCOV
1619
                        return collabQuota;
×
1620
                }
1621

1622
                void setDefaultCollabQuota(long collabQuota) {
UNCOV
1623
                        this.collabQuota = collabQuota;
×
UNCOV
1624
                }
×
1625

1626
                /**
1627
                 * @return Cron expression that says when we consolidate job quotas into
1628
                 *         the main quota table.
1629
                 */
1630
                @NotBlank
1631
                public String getConsolidationSchedule() {
1632
                        return consolidationSchedule;
2✔
1633
                }
1634

1635
                void setConsolidationSchedule(String consolidationSchedule) {
UNCOV
1636
                        this.consolidationSchedule = consolidationSchedule;
×
UNCOV
1637
                }
×
1638

1639
                /**
1640
                 * @return The URL of an NMPI server that deals with quota.
1641
                 *         May be blank, meaning there isn't one.
1642
                 */
1643
                public String getNMPIUrl() {
1644
                        return nmpiUrl;
2✔
1645
                }
1646

1647
                void setNMPIUrl(String nmpiUrl) {
1648
                        this.nmpiUrl = nmpiUrl;
×
UNCOV
1649
                }
×
1650

1651
                /**
1652
                 * @return The API Key to use to access the NMPI server.
1653
                 *         May be blank if @linkplain(#nmpiUrl) is blank.
1654
                 */
1655
                public String getNMPIApiKey() {
UNCOV
1656
                        return nmpiApiKey;
×
1657
                }
1658

1659
                void setNMPIApiKey(String nmpiApiKey) {
UNCOV
1660
                        this.nmpiApiKey = nmpiApiKey;
×
UNCOV
1661
                }
×
1662

1663
                /**
1664
                 * @return The platform to look for on the NMPI server.
1665
                 */
1666
                public String getNMPIPlaform() {
UNCOV
1667
                        return nmpiPlatform;
×
1668
                }
1669

1670
                void setNMPIPlatform(String nmpiPlatform) {
UNCOV
1671
                        this.nmpiPlatform = nmpiPlatform;
×
UNCOV
1672
                }
×
1673
        }
1674

1675
        /** Controls how Spalloc talks to BMPs on machines. */
1676
        public static class TxrxProperties {
1677
                /**
1678
                 * How long between when we send requests to the BMP control tasks.
1679
                 */
1680
                private Duration period;
1681

1682
                /** The basic wait time used by the BMP control tasks. */
1683
                private Duration probeInterval;
1684

1685
                /** Number of attempts that will be made to switch on a board. */
1686
                private int powerAttempts;
1687

1688
                /** Number of attempts that will be made to bring up an FPGA. */
1689
                private int fpgaAttempts;
1690

1691
                /**
1692
                 * Whether to reload the FPGA bitfiles when they don't come up
1693
                 * correctly.
1694
                 */
1695
                private boolean fpgaReload;
1696

1697
                /**
1698
                 * Number of attempts that will be made to bring up a transceiver,
1699
                 * provided the failures are due to timeouts and not outright network
1700
                 * errors. Note that a failure to bring up a transceiver is lethal to
1701
                 * the service.
1702
                 */
1703
                private int buildAttempts;
1704

1705
                /** Whether to use a dummy transceiver. Useful for testing only. */
1706
                private boolean dummy;
1707

1708
                /** The time a board has to be off before it can be powered on. */
1709
                private Duration offWaitTime;
1710

1711
                /**
1712
                 * @param period
1713
                 *            How long between when we send requests to the BMP control
1714
                 *            tasks.
1715
                 * @param probeInterval
1716
                 *            The basic wait time used by the BMP control tasks.
1717
                 * @param powerAttempts
1718
                 *            Number of attempts that will be made to switch on a board.
1719
                 * @param fpgaAttempts
1720
                 *            Number of attempts that will be made to bring up an FPGA.
1721
                 * @param fpgaReload
1722
                 *            Whether to reload the FPGA bitfiles when they don't come
1723
                 *            up correctly.
1724
                 * @param buildAttempts
1725
                 *            Number of attempts that will be made to bring up a
1726
                 *            transceiver, provided the failures are due to timeouts and
1727
                 *            not outright network errors. Note that a failure to bring
1728
                 *            up a transceiver is lethal to the service.
1729
                 * @param dummy
1730
                 *            Whether to use a dummy transceiver. Useful for testing
1731
                 *            only.
1732
                 * @param offWaitTime
1733
                 *            How long to wait between powering off and powering on
1734
                 *            a board.
1735
                 */
1736
                @ConstructorBinding
1737
                public TxrxProperties(@DefaultValue("10s") Duration period,
1738
                                @DefaultValue("15s") Duration probeInterval,
1739
                                @DefaultValue("2") int powerAttempts,
1740
                                @DefaultValue("3") int fpgaAttempts,
1741
                                @DefaultValue("false") boolean fpgaReload,
1742
                                @DefaultValue("5") int buildAttempts,
1743
                                @DefaultValue("false") boolean dummy,
1744
                                @DefaultValue("30s") Duration offWaitTime) {
2✔
1745
                        this.period = period;
2✔
1746
                        this.probeInterval = probeInterval;
2✔
1747
                        this.powerAttempts = powerAttempts;
2✔
1748
                        this.fpgaAttempts = fpgaAttempts;
2✔
1749
                        this.fpgaReload = fpgaReload;
2✔
1750
                        this.buildAttempts = buildAttempts;
2✔
1751
                        this.dummy = dummy;
2✔
1752
                        this.offWaitTime = offWaitTime;
2✔
1753
                }
2✔
1754

1755
                /**
1756
                 * How long between when we send requests to the BMP control tasks.
1757
                 *
1758
                 * @return How long between when we send requests to the BMP control
1759
                 *         tasks.
1760
                 */
1761
                @NotNull
1762
                public Duration getPeriod() {
1763
                        return period;
2✔
1764
                }
1765

1766
                void setPeriod(Duration period) {
UNCOV
1767
                        this.period = period;
×
UNCOV
1768
                }
×
1769

1770
                /** @return The basic wait time used by the BMP control tasks. */
1771
                @NotNull
1772
                public Duration getProbeInterval() {
1773
                        return probeInterval;
2✔
1774
                }
1775

1776
                @NotNull
1777
                public Duration getOffWaitTime() {
1778
                        return offWaitTime;
2✔
1779
                }
1780

1781
                void setProbeInterval(Duration probeInterval) {
UNCOV
1782
                        this.probeInterval = probeInterval;
×
UNCOV
1783
                }
×
1784

1785
                /**
1786
                 * @return Number of attempts that will be made to switch on a board.
1787
                 */
1788
                @Positive
1789
                public int getPowerAttempts() {
1790
                        return powerAttempts;
2✔
1791
                }
1792

1793
                void setPowerAttempts(int powerAttempts) {
UNCOV
1794
                        this.powerAttempts = powerAttempts;
×
1795
                }
×
1796

1797
                /** @return Number of attempts that will be made to bring up an FPGA. */
1798
                @Positive
1799
                public int getFpgaAttempts() {
1800
                        return fpgaAttempts;
2✔
1801
                }
1802

1803
                void setFpgaAttempts(int fpgaAttempts) {
UNCOV
1804
                        this.fpgaAttempts = fpgaAttempts;
×
UNCOV
1805
                }
×
1806

1807
                /**
1808
                 * @return Whether to reload the FPGA bitfiles when they don't come up
1809
                 *         correctly.
1810
                 */
1811
                public boolean isFpgaReload() {
UNCOV
1812
                        return fpgaReload;
×
1813
                }
1814

1815
                void setFpgaReload(boolean fpgaReload) {
UNCOV
1816
                        this.fpgaReload = fpgaReload;
×
UNCOV
1817
                }
×
1818

1819
                /**
1820
                 * Number of attempts that will be made to bring up a transceiver,
1821
                 * provided the failures are due to timeouts and not outright network
1822
                 * errors. Note that a failure to bring up a transceiver is lethal to
1823
                 * the service.
1824
                 *
1825
                 * @return Number of attempts that will be made to bring up a
1826
                 *         transceiver.
1827
                 */
1828
                @Positive
1829
                public int getBuildAttempts() {
1830
                        return buildAttempts;
2✔
1831
                }
1832

1833
                void setBuildAttempts(int value) {
UNCOV
1834
                        this.buildAttempts = value;
×
UNCOV
1835
                }
×
1836

1837
                /**
1838
                 * Useful for testing only.
1839
                 *
1840
                 * @return Whether to use a dummy transceiver.
1841
                 */
1842
                public boolean isDummy() {
1843
                        return dummy;
2✔
1844
                }
1845

1846
                void setDummy(boolean dummy) {
UNCOV
1847
                        this.dummy = dummy;
×
UNCOV
1848
                }
×
1849
        }
1850

1851
        /**
1852
         * The properties of a {@link DataSource}, describing how to make a database
1853
         * connection.
1854
         */
1855
        @UsedInJavadocOnly(DataSource.class)
1856
        public static class DataSourceProperties {
1857
                /** URL for creating a connection. */
1858
                @NotEmpty
1859
                private String jdbcUrl;
1860

1861
                /** User name for the connection. */
1862
                private String username;
1863

1864
                /** Password for the connection. */
1865
                private String password;
1866

1867
                /**
1868
                 * @param jdbcUrl
1869
                 *            URL for creating a connection.
1870
                 * @param username
1871
                 *            User name for the connection.
1872
                 * @param password
1873
                 *            Password for the connection.
1874
                 */
1875
                @ConstructorBinding
1876
                public DataSourceProperties(
1877
                                @DefaultValue("jdbc:sqlite:/fix.me") String jdbcUrl,
1878
                                @DefaultValue("sa") String username,
1879
                                @DefaultValue("*") String password) {
2✔
1880
                        this.jdbcUrl = jdbcUrl;
2✔
1881
                        this.username = username;
2✔
1882
                        this.password = password;
2✔
1883
                }
2✔
1884

1885
                /** @return URL for creating a connection. */
1886
                public String getJdbcUrl() {
UNCOV
1887
                        return jdbcUrl;
×
1888
                }
1889

1890
                void setJdbcUrl(String jdbcUrl) {
1891
                        this.jdbcUrl = jdbcUrl;
×
UNCOV
1892
                }
×
1893

1894
                /** @return User name for the connection. */
1895
                public String getUsername() {
UNCOV
1896
                        return username;
×
1897
                }
1898

1899
                void setUsername(String username) {
1900
                        this.username = username;
×
UNCOV
1901
                }
×
1902

1903
                /** @return Password for the connection. */
1904
                public String getPassword() {
UNCOV
1905
                        return password;
×
1906
                }
1907

1908
                void setPassword(String password) {
UNCOV
1909
                        this.password = password;
×
UNCOV
1910
                }
×
1911
        }
1912

1913
        /** Additional database configuration. */
1914
        public static class DBProperties {
1915
                private static final int MAX_ANALYSIS = 1000;
1916

1917
                private static final int MIN_ANALYSIS = 100;
1918

1919
                /** How long to wait to get a database lock. */
1920
                private Duration timeout;
1921

1922
                /** Whether to send details of SQL-related exceptions to users. */
1923
                private boolean debugFailures;
1924

1925
                /**
1926
                 * Amount of effort to spend on DB optimisation on application close.
1927
                 * See the SQLite documentation for meaning. Note that this is spent by
1928
                 * every worker thread that touches the database.
1929
                 */
1930
                private int analysisLimit;
1931

1932
                /**
1933
                 * Whether to collect and write query performance metrics to the log on
1934
                 * termination.
1935
                 */
1936
                private boolean performanceLog;
1937

1938
                /**
1939
                 * If the performance log is enabled, also write the EXPLAIN of the code
1940
                 * to the log on termination (for slow queries only).
1941
                 */
1942
                private boolean autoExplain;
1943

1944
                /**
1945
                 * Performance stats not reported for queries with a max less than this
1946
                 * (in &mu;s).
1947
                 */
1948
                private double performanceThreshold;
1949

1950
                /** Number of times to try to take the lock in a transaction. */
1951
                private int lockTries;
1952

1953
                /** Delay after transaction failure before retrying. */
1954
                private Duration lockFailedDelay;
1955

1956
                /** Time delay before we issue a warning on transaction end. */
1957
                private Duration lockNoteThreshold;
1958

1959
                /**
1960
                 * Time delay before we issue a warning during the execution of a
1961
                 * transaction.
1962
                 */
1963
                private Duration lockWarnThreshold;
1964

1965
                /** Whether to determine the caller when doing transaction logging. */
1966
                private boolean enableExpensiveTransactionDebugging;
1967

1968
                /**
1969
                 * @param timeout
1970
                 *            How long to wait to get a database lock.
1971
                 * @param debugFailures
1972
                 *            Whether to send details of SQL-related exceptions to
1973
                 *            users.
1974
                 * @param analysisLimit
1975
                 *            Amount of effort to spend on DB optimisation on
1976
                 *            application close. See the SQLite documentation for
1977
                 *            meaning. Note that this is spent by every worker thread
1978
                 *            that touches the database.
1979
                 * @param performanceLog
1980
                 *            Whether to collect and write query performance metrics to
1981
                 *            the log on termination.
1982
                 * @param autoExplain
1983
                 *            If the performance log is enabled, also write the EXPLAIN
1984
                 *            of the code to the log on termination (for slow queries
1985
                 *            only).
1986
                 * @param performanceThreshold
1987
                 *            Performance stats not reported for queries with a max less
1988
                 *            than this (in &mu;s).
1989
                 * @param lockTries
1990
                 *            Number of times to try to take the lock in a transaction.
1991
                 * @param lockFailedDelay
1992
                 *            Delay after transaction failure before retrying.
1993
                 * @param lockNoteThreshold
1994
                 *            Time delay before we issue a warning on transaction end.
1995
                 * @param lockWarnThreshold
1996
                 *            Time delay before we issue a warning during the execution
1997
                 *            of a transaction.
1998
                 * @param enableExpensiveTransactionDebugging
1999
                 *            Whether to determine the caller when doing transaction
2000
                 *            logging.
2001
                 */
2002
                @ConstructorBinding
2003
                public DBProperties(@DefaultValue("1s") Duration timeout,
2004
                                @DefaultValue("false") boolean debugFailures,
2005
                                @DefaultValue("400") int analysisLimit,
2006
                                @DefaultValue("false") boolean performanceLog,
2007
                                @DefaultValue("true") boolean autoExplain,
2008
                                @DefaultValue("1e6") double performanceThreshold,
2009
                                @DefaultValue("3") int lockTries,
2010
                                @DefaultValue("100ms") Duration lockFailedDelay,
2011
                                @DefaultValue("50ms") Duration lockNoteThreshold,
2012
                                @DefaultValue("100ms") Duration lockWarnThreshold,
2013
                                @DefaultValue("false") //
2014
                                boolean enableExpensiveTransactionDebugging) {
2✔
2015
                        this.timeout = timeout;
2✔
2016
                        this.debugFailures = debugFailures;
2✔
2017
                        this.analysisLimit = analysisLimit;
2✔
2018
                        this.performanceLog = performanceLog;
2✔
2019
                        this.autoExplain = autoExplain;
2✔
2020
                        this.performanceThreshold = performanceThreshold;
2✔
2021
                        this.lockTries = lockTries;
2✔
2022
                        this.lockFailedDelay = lockFailedDelay;
2✔
2023
                        this.lockNoteThreshold = lockNoteThreshold;
2✔
2024
                        this.lockWarnThreshold = lockWarnThreshold;
2✔
2025
                        this.enableExpensiveTransactionDebugging =
2✔
2026
                                        enableExpensiveTransactionDebugging;
2027
                }
2✔
2028

2029
                /** @return How long to wait to get a database lock. */
2030
                @NotNull
2031
                public Duration getTimeout() {
2032
                        return timeout;
2✔
2033
                }
2034

2035
                void setTimeout(Duration timeout) {
2036
                        this.timeout = timeout;
×
2037
                }
×
2038

2039
                /**
2040
                 * @return Whether to send details of SQL-related exceptions to users.
2041
                 */
2042
                public boolean isDebugFailures() {
UNCOV
2043
                        return debugFailures;
×
2044
                }
2045

2046
                void setDebugFailures(boolean debugFailures) {
UNCOV
2047
                        this.debugFailures = debugFailures;
×
UNCOV
2048
                }
×
2049

2050
                /**
2051
                 * Amount of effort to spend on DB optimisation on application close.
2052
                 * See the SQLite documentation for meaning. Note that this is spent by
2053
                 * every worker thread that touches the database.
2054
                 *
2055
                 * @return Amount of effort to spend on DB optimisation on application
2056
                 *         close.
2057
                 * @see <a href="https://sqlite.org/lang_analyze.html">SQLite docs</a>
2058
                 */
2059
                @Min(MIN_ANALYSIS)
2060
                @Max(MAX_ANALYSIS)
2061
                public int getAnalysisLimit() {
2062
                        return analysisLimit;
2✔
2063
                }
2064

2065
                void setAnalysisLimit(int analysisLimit) {
UNCOV
2066
                        this.analysisLimit = analysisLimit;
×
UNCOV
2067
                }
×
2068

2069
                /**
2070
                 * @return Whether to collect and write query performance metrics to the
2071
                 *         log on termination. Note that this is checked both when
2072
                 *         recording performance (on each database query) and when the
2073
                 *         log writes happen (on termination).
2074
                 */
2075
                public final boolean isPerformanceLog() {
UNCOV
2076
                        return performanceLog;
×
2077
                }
2078

2079
                void setPerformanceLog(boolean log) {
UNCOV
2080
                        this.performanceLog = log;
×
UNCOV
2081
                }
×
2082

2083
                /**
2084
                 * @return Whether, if the performance log is enabled, to also write the
2085
                 *         EXPLAIN of the code to the log on termination (for slow
2086
                 *         queries only).
2087
                 */
2088
                public final boolean isAutoExplain() {
UNCOV
2089
                        return autoExplain;
×
2090
                }
2091

2092
                void setAutoExplain(boolean flag) {
UNCOV
2093
                        this.autoExplain = flag;
×
UNCOV
2094
                }
×
2095

2096
                /**
2097
                 * @return Performance stats are not reported for queries with a max
2098
                 *         less than this, in microseconds.
2099
                 */
2100
                @Positive
2101
                public final double getPerformanceThreshold() {
2102
                        return performanceThreshold;
2✔
2103
                }
2104

2105
                void setPerformanceThreshold(double threshold) {
2106
                        this.performanceThreshold = threshold;
×
UNCOV
2107
                }
×
2108

2109
                /** @return Number of times to try to take the lock in a transaction. */
2110
                @Positive
2111
                public int getLockTries() {
2112
                        return lockTries;
2✔
2113
                }
2114

2115
                void setLockTries(int lockTries) {
2116
                        this.lockTries = lockTries;
×
UNCOV
2117
                }
×
2118

2119
                /** @return Delay after transaction failure before retrying. */
2120
                @NotNull
2121
                public Duration getLockFailedDelay() {
2122
                        return lockFailedDelay;
2✔
2123
                }
2124

2125
                void setLockFailedDelay(Duration value) {
2126
                        this.lockFailedDelay = value;
×
UNCOV
2127
                }
×
2128

2129
                /** @return Time delay before we issue a warning on transaction end. */
2130
                @NotNull
2131
                public Duration getLockNoteThreshold() {
2132
                        return lockNoteThreshold;
2✔
2133
                }
2134

2135
                void setLockNoteThreshold(Duration value) {
UNCOV
2136
                        this.lockNoteThreshold = value;
×
UNCOV
2137
                }
×
2138

2139
                /**
2140
                 * @return Time delay before we issue a warning during the execution of
2141
                 *         a transaction.
2142
                 */
2143
                @NotNull
2144
                public Duration getLockWarnThreshold() {
2145
                        return lockWarnThreshold;
2✔
2146
                }
2147

2148
                void setLockWarnThreshold(Duration value) {
UNCOV
2149
                        this.lockWarnThreshold = value;
×
2150
                }
×
2151

2152
                /**
2153
                 * @return Whether to determine the caller when doing transaction
2154
                 *         logging.
2155
                 */
2156
                public boolean isEnableExpensiveTransactionDebugging() {
UNCOV
2157
                        return enableExpensiveTransactionDebugging;
×
2158
                }
2159

2160
                void setEnableExpensiveTransactionDebugging(boolean value) {
UNCOV
2161
                        this.enableExpensiveTransactionDebugging = value;
×
UNCOV
2162
                }
×
2163
        }
2164

2165
        /** Settings relating to the v1 spalloc configuration interface. */
2166
        public static class CompatibilityProperties {
2167
                /**
2168
                 * Whether to turn the spalloc version 1 compatibility service interface
2169
                 * on.
2170
                 */
2171
                private boolean enable;
2172

2173
                /**
2174
                 * The number of threads to use to service the v1 clients. 0 means no
2175
                 * limit.
2176
                 */
2177
                private int threadPoolSize;
2178

2179
                /** What hostname to run the spalloc v1 compatibility service on. */
2180
                private String host;
2181

2182
                /** What TCP port to run the spalloc v1 compatibility service on. */
2183
                private int port;
2184

2185
                /** How long to wait for the executor to shut down, maximum. */
2186
                private Duration shutdownTimeout;
2187

2188
                /**
2189
                 * How long to wait for a message to be received. Making this too short
2190
                 * makes the service more expensive. Making this too long makes the
2191
                 * service difficult to shut down correctly.
2192
                 */
2193
                private Duration receiveTimeout;
2194

2195
                /**
2196
                 * What user to run jobs submitted through the spalloc v1 compatibility
2197
                 * service with. We recommend that this user exists but is disabled
2198
                 * (i.e., login using this service identity need not be supported).
2199
                 */
2200
                private String serviceUser;
2201

2202
                /**
2203
                 * What group to run jobs submitted through the spalloc v1 compatibility
2204
                 * service against. This group needs to exist, and the service user
2205
                 * needs to be a member of it, but does not need to have a quota set.
2206
                 */
2207
                private String serviceGroup;
2208

2209
                /**
2210
                 * How long to pass to the spalloc core to wait for timeouts relating to
2211
                 * message notifications (i.e., due to machine or job status changes).
2212
                 */
2213
                private Duration notifyWaitTime;
2214

2215
                /** The default value for the keepalive property of jobs. */
2216
                private Duration defaultKeepalive;
2217

2218
                /**
2219
                 * @param enable
2220
                 *            Whether to turn the spalloc version 1 compatibility
2221
                 *            service interface on.
2222
                 * @param threadPoolSize
2223
                 *            The number of threads to use to service the v1 clients. 0
2224
                 *            means no limit.
2225
                 * @param host
2226
                 *            What hostname to run the spalloc v1 compatibility service
2227
                 *            on.
2228
                 * @param port
2229
                 *            What TCP port to run the spalloc v1 compatibility service
2230
                 *            on.
2231
                 * @param serviceUser
2232
                 *            What user to run jobs submitted through the spalloc v1
2233
                 *            compatibility service with. We recommend that this user
2234
                 *            exists but is disabled (i.e., login using this service
2235
                 *            identity need not be supported).
2236
                 * @param serviceGroup
2237
                 *            What group to run jobs submitted through the spalloc v1
2238
                 *            compatibility service against. This group needs to exist,
2239
                 *            and the service user needs to be a member of it, but does
2240
                 *            not need to have a quota set.
2241
                 * @param receiveTimeout
2242
                 *            How long to wait for a message to be received. Making this
2243
                 *            too short makes the service more expensive. Making this
2244
                 *            too long makes the service difficult to shut down
2245
                 *            correctly.
2246
                 * @param shutdownTimeout
2247
                 *            How long to wait for the executor to shut down, maximum.
2248
                 * @param notifyWaitTime
2249
                 *            How long to pass to the spalloc core to wait for timeouts
2250
                 *            relating to message notifications (i.e., due to machine or
2251
                 *            job status changes).
2252
                 * @param defaultKeepalive
2253
                 *            The default value for the keepalive property of jobs.
2254
                 */
2255
                @ConstructorBinding
2256
                public CompatibilityProperties(@DefaultValue("false") boolean enable,
2257
                                @DefaultValue("0") int threadPoolSize,
2258
                                @DefaultValue("0.0.0.0") String host,
2259
                                @DefaultValue("22244") int port,
2260
                                @DefaultValue("") String serviceUser,
2261
                                @DefaultValue("") String serviceGroup,
2262
                                @DefaultValue("2000ms") Duration receiveTimeout,
2263
                                @DefaultValue("3s") Duration shutdownTimeout,
2264
                                @DefaultValue("1m") Duration notifyWaitTime,
2265
                                @DefaultValue("1m") Duration defaultKeepalive) {
2✔
2266
                        this.enable = enable;
2✔
2267
                        this.threadPoolSize = threadPoolSize;
2✔
2268
                        this.host = host;
2✔
2269
                        this.port = port;
2✔
2270
                        this.serviceUser = serviceUser;
2✔
2271
                        this.serviceGroup = serviceGroup;
2✔
2272
                        this.receiveTimeout = receiveTimeout;
2✔
2273
                        this.shutdownTimeout = shutdownTimeout;
2✔
2274
                        this.notifyWaitTime = notifyWaitTime;
2✔
2275
                        this.defaultKeepalive = defaultKeepalive;
2✔
2276
                }
2✔
2277

2278
                /**
2279
                 * @return Whether to turn the spalloc version 1 compatibility service
2280
                 *         interface on.
2281
                 */
2282
                public boolean isEnable() {
2283
                        return enable;
2✔
2284
                }
2285

2286
                void setEnable(boolean enable) {
UNCOV
2287
                        this.enable = enable;
×
2288
                }
×
2289

2290
                /**
2291
                 * @return The number of threads to use to service the v1 clients. 0
2292
                 *         means no limit (slightly dangerous).
2293
                 */
2294
                @PositiveOrZero
2295
                public int getThreadPoolSize() {
2296
                        return threadPoolSize;
2✔
2297
                }
2298

2299
                void setThreadPoolSize(int threadPoolSize) {
UNCOV
2300
                        this.threadPoolSize = threadPoolSize;
×
2301
                }
×
2302

2303
                /**
2304
                 * @return What host address to run the spalloc v1 compatibility service
2305
                 *         on.
2306
                 */
2307
                @NotBlank
2308
                public String getHost() {
2309
                        return host;
2✔
2310
                }
2311

2312
                void setHost(String host) {
2313
                        this.host = host;
×
2314
                }
×
2315

2316
                /**
2317
                 * @return What TCP port to run the spalloc v1 compatibility service on.
2318
                 */
2319
                @TCPPort(ephemeral = false)
2320
                public int getPort() {
2321
                        return port;
2✔
2322
                }
2323

2324
                void setPort(int port) {
UNCOV
2325
                        this.port = port;
×
UNCOV
2326
                }
×
2327

2328
                /**
2329
                 * What user to run jobs submitted through the spalloc v1 compatibility
2330
                 * service with. We recommend that this user exists but is disabled
2331
                 * (i.e., login using this service identity need not be supported).
2332
                 *
2333
                 * @return What user to run jobs submitted through the spalloc v1
2334
                 *         compatibility service with.
2335
                 */
2336
                public String getServiceUser() {
2337
                        return serviceUser;
2✔
2338
                }
2339

2340
                void setServiceUser(String serviceUser) {
UNCOV
2341
                        this.serviceUser = serviceUser;
×
UNCOV
2342
                }
×
2343

2344
                @Keep
2345
                @AssertTrue(message = "a service username must be given "
2346
                                + "if the v1 service is enabled")
2347
                private boolean isValidUserIfEnabled() {
2348
                        return !enable
2!
2349
                                        || (nonNull(serviceUser) && !serviceUser.isBlank());
2!
2350
                }
2351

2352
                /**
2353
                 * What group to run jobs submitted through the spalloc v1 compatibility
2354
                 * service against. This group needs to exist, and the service user
2355
                 * needs to be a member of it, but does not need to have a quota set.
2356
                 *
2357
                 * @return What group to run jobs submitted through the spalloc v1
2358
                 *         compatibility service against.
2359
                 */
2360
                public String getServiceGroup() {
2361
                        return serviceGroup;
2✔
2362
                }
2363

2364
                void setServiceGroup(String serviceUser) {
UNCOV
2365
                        this.serviceGroup = serviceUser;
×
UNCOV
2366
                }
×
2367

2368
                @Keep
2369
                @AssertTrue(message = "a service group must be given "
2370
                                + "if the v1 service is enabled")
2371
                private boolean isValidGroupIfEnabled() {
2372
                        return !enable || (nonNull(serviceGroup)
2!
2373
                                        && !serviceGroup.isBlank());
2!
2374
                }
2375

2376
                /**
2377
                 * @return How long to wait for the executor to shut down, maximum.
2378
                 */
2379
                @NotNull
2380
                public Duration getShutdownTimeout() {
2381
                        return shutdownTimeout;
2✔
2382
                }
2383

2384
                void setShutdownTimeout(Duration value) {
UNCOV
2385
                        this.shutdownTimeout = value;
×
UNCOV
2386
                }
×
2387

2388
                /**
2389
                 * Making this too short makes the service more expensive. Making this
2390
                 * too long makes the service difficult to shut down correctly. (Failure
2391
                 * to receive in this time triggers an exception, but it needs to be
2392
                 * fairly frequent or the thread can't be interrupted.)
2393
                 *
2394
                 * @return How long to wait for a message to be received.
2395
                 */
2396
                @NotNull
2397
                public Duration getReceiveTimeout() {
2398
                        return receiveTimeout;
2✔
2399
                }
2400

2401
                void setReceiveTimeout(Duration value) {
UNCOV
2402
                        this.receiveTimeout = value;
×
UNCOV
2403
                }
×
2404

2405
                /**
2406
                 * @return How long to pass to the spalloc core to wait for timeouts
2407
                 *         relating to message notifications (i.e., due to machine or
2408
                 *         job status changes).
2409
                 */
2410
                @NotNull
2411
                public Duration getNotifyWaitTime() {
2412
                        return notifyWaitTime;
2✔
2413
                }
2414

2415
                void setNotifyWaitTime(Duration value) {
2416
                        this.notifyWaitTime = value;
×
2417
                }
×
2418

2419
                /**
2420
                 * @return The default value for the keepalive property of jobs.
2421
                 */
2422
                @NotNull
2423
                public Duration getDefaultKeepalive() {
2424
                        return defaultKeepalive;
2✔
2425
                }
2426

2427
                void setDefaultKeepalive(Duration value) {
UNCOV
2428
                        this.defaultKeepalive = value;
×
UNCOV
2429
                }
×
2430
        }
2431

2432
        /** Settings for the proxies. */
2433
        public static class ProxyProperties {
2434
                /** Whether to enable the UDP proxy subsystem. */
2435
                private boolean enable;
2436

2437
                /**
2438
                 * Whether to log the number of packets read and written on each
2439
                 * channel.
2440
                 */
2441
                private boolean logWriteCounts;
2442

2443
                /**
2444
                 * The address for local proxied sockets to listen on if they're not
2445
                 * being bound to a specific board. If empty, that type of socket will
2446
                 * be disabled.
2447
                 */
2448
                private String localHost;
2449

2450
                /**
2451
                 * @param enable
2452
                 *            Whether to enable the UDP proxy subsystem.
2453
                 * @param logWriteCounts
2454
                 *            Whether to log the number of packets read and written on
2455
                 *            each channel.
2456
                 * @param localHost
2457
                 *            The address for local proxied sockets to listen on if
2458
                 *            they're not being bound to a specific board. If empty,
2459
                 *            that type of socket will be disabled.
2460
                 */
2461
                @ConstructorBinding
2462
                public ProxyProperties(@DefaultValue("true") boolean enable,
2463
                                @DefaultValue("false") boolean logWriteCounts,
2464
                                @DefaultValue("") String localHost) {
2✔
2465
                        this.enable = enable;
2✔
2466
                        this.logWriteCounts = logWriteCounts;
2✔
2467
                        this.localHost = localHost;
2✔
2468
                }
2✔
2469

2470
                /** @return Whether to enable the UDP proxy subsystem. */
2471
                public boolean isEnable() {
2472
                        return enable;
2✔
2473
                }
2474

2475
                void setEnable(boolean enable) {
2476
                        this.enable = enable;
×
UNCOV
2477
                }
×
2478

2479
                /**
2480
                 * @return Whether to log the number of packets read and written on each
2481
                 *         channel.
2482
                 */
2483
                public boolean isLogWriteCounts() {
UNCOV
2484
                        return logWriteCounts;
×
2485
                }
2486

2487
                void setLogWriteCounts(boolean logWriteCounts) {
UNCOV
2488
                        this.logWriteCounts = logWriteCounts;
×
UNCOV
2489
                }
×
2490

2491
                /**
2492
                 * @return The address for local proxied sockets to listen on if
2493
                 *         they're not being bound to a specific board. If empty, that
2494
                 *         type of socket will be disabled.
2495
                 */
2496
                @NotNull
2497
                @IPAddress(emptyOK = true)
2498
                public String getLocalHost() {
2499
                        return localHost;
2✔
2500
                }
2501

2502
                void setLocalHost(String localHost) {
UNCOV
2503
                        this.localHost = localHost;
×
UNCOV
2504
                }
×
2505
        }
2506

2507
        /** Settings for control of the administrative state of a machine. */
2508
        public static class StateControlProperties {
2509
                /** How long to wait between polls of the BMP controller. */
2510
                private Duration blacklistPoll;
2511

2512
                /** How long to wait for a blacklist operation to complete. */
2513
                private Duration blacklistTimeout;
2514

2515
                /**
2516
                 * How many board serial numbers to read from a full machine at once
2517
                 * when synchronizing the overall state?
2518
                 */
2519
                private int serialReadBatchSize;
2520

2521
                /**
2522
                 * How many blacklists to read from a full machine at once when
2523
                 * synchronizing the overall state?
2524
                 */
2525
                private int blacklistReadBatchSize;
2526

2527
                /**
2528
                 * @param blacklistPoll
2529
                 *            How long to wait between polls of the BMP controller.
2530
                 * @param blacklistTimeout
2531
                 *            How long to wait for a blacklist operation to complete.
2532
                 * @param serialReadBatchSize
2533
                 *            How many board serial numbers to read from a full machine
2534
                 *            at once when synchronizing the overall state?
2535
                 * @param blacklistReadBatchSize
2536
                 *            How many blacklists to read from a full machine at once
2537
                 *            when synchronizing the overall state?
2538
                 */
2539
                @ConstructorBinding
2540
                public StateControlProperties(
2541
                                @DefaultValue("15s") Duration blacklistPoll,
2542
                                @DefaultValue("60s") Duration blacklistTimeout,
2543
                                @DefaultValue("24") int serialReadBatchSize,
2544
                                @DefaultValue("6") int blacklistReadBatchSize) {
2✔
2545
                        this.blacklistPoll = blacklistPoll;
2✔
2546
                        this.blacklistTimeout = blacklistTimeout;
2✔
2547
                        this.serialReadBatchSize = serialReadBatchSize;
2✔
2548
                        this.blacklistReadBatchSize = blacklistReadBatchSize;
2✔
2549
                }
2✔
2550

2551
                /** @return How long to wait between polls of the BMP controller. */
2552
                @NotNull
2553
                public Duration getBlacklistPoll() {
2554
                        return blacklistPoll;
2✔
2555
                }
2556

2557
                void setBlacklistPoll(Duration blacklistPoll) {
UNCOV
2558
                        this.blacklistPoll = blacklistPoll;
×
UNCOV
2559
                }
×
2560

2561
                /** @return How long to wait for a blacklist operation to complete. */
2562
                @NotNull
2563
                public Duration getBlacklistTimeout() {
2564
                        return blacklistTimeout;
2✔
2565
                }
2566

2567
                void setBlacklistTimeout(Duration blacklistTimeout) {
2568
                        this.blacklistTimeout = blacklistTimeout;
×
UNCOV
2569
                }
×
2570

2571
                /**
2572
                 * @return How many board serial numbers to read from a full machine at
2573
                 *         once when synchronizing the overall state?
2574
                 */
2575
                @Positive
2576
                public int getSerialReadBatchSize() {
2577
                        return serialReadBatchSize;
2✔
2578
                }
2579

2580
                void setSerialReadBatchSize(int serialReadBatchSize) {
2581
                        this.serialReadBatchSize = serialReadBatchSize;
×
UNCOV
2582
                }
×
2583

2584
                /**
2585
                 * @return How many blacklists to read from a full machine at once when
2586
                 *         synchronizing the overall state?
2587
                 */
2588
                @Positive
2589
                public int getBlacklistReadBatchSize() {
2590
                        return blacklistReadBatchSize;
2✔
2591
                }
2592

2593
                void setBlacklistReadBatchSize(int blacklistReadBatchSize) {
UNCOV
2594
                        this.blacklistReadBatchSize = blacklistReadBatchSize;
×
UNCOV
2595
                }
×
2596
        }
2597
}
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