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

SpiNNakerManchester / JavaSpiNNaker / 15113742418

19 May 2025 01:03PM UTC coverage: 37.528% (-0.8%) from 38.278%
15113742418

Pull #1227

github

rowleya
Merge branch 'master' into emergency_stop
Pull Request #1227: Emergency stop

114 of 152 new or added lines in 10 files covered. (75.0%)

243 existing lines in 6 files now uncovered.

9062 of 24147 relevant lines covered (37.53%)

1.12 hits per line

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

49.79
/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 javax.validation.Valid;
26
import javax.validation.constraints.AssertTrue;
27
import javax.validation.constraints.Email;
28
import javax.validation.constraints.Max;
29
import javax.validation.constraints.Min;
30
import javax.validation.constraints.NotBlank;
31
import javax.validation.constraints.NotEmpty;
32
import javax.validation.constraints.NotNull;
33
import javax.validation.constraints.Positive;
34
import javax.validation.constraints.PositiveOrZero;
35

36
import org.springframework.boot.context.properties.ConfigurationProperties;
37
import org.springframework.boot.context.properties.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
@ConstructorBinding
57
@Validated
58
public class SpallocProperties {
59
        /** Path to the main database file. */
60
        private File databasePath;
61

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

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

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

74
        private HistoricalDataProperties historicalData;
75

76
        private KeepaliveProperties keepalive;
77

78
        private AllocatorProperties allocator;
79

80
        private AuthProperties auth;
81

82
        private QuotaProperties quota;
83

84
        private TxrxProperties transceiver;
85

86
        private DBProperties sqlite;
87

88
        private CompatibilityProperties compat;
89

90
        private ProxyProperties proxy;
91

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

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

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

101
        /**
102
         * @param databasePath
103
         *            Path to the main database file.
104
         * @param wait
105
         *            How long should long calls take before returning anyway?
106
         * @param pause
107
         *            Whether to pause <em>all</em> periodic callbacks. Probably
108
         *            only useful for debugging and testing.
109
         * @param workingDirectory
110
         *            The main working directory. Referred to by other properties.
111
         * @param allocator
112
         *            Properties relating to the allocation engine.
113
         * @param auth
114
         *            Properties relating to authentication and authorization.
115
         * @param compat
116
         *            Properties relating to the Spalloc v1 compatibility layer.
117
         * @param historicalData
118
         *            Properties relating to historical data management.
119
         * @param keepalive
120
         *            Properties relating to job keep-alive messages.
121
         * @param proxy
122
         *            Properties relating to the SDP proxying.
123
         * @param quota
124
         *            Properties relating to quota management.
125
         * @param sqlite
126
         *            Properties relating to the details of working with SQLite.
127
         * @param reportEmail
128
         *            Properties relating to board issue reporting.
129
         * @param transceiver
130
         *            Properties relating to low-level transceiver control and the
131
         *            BMPs.
132
         * @param stateControl
133
         *            Properties relating to control of the overall machine state.
134
         * @param datasource
135
         *            The database connection configuration.
136
         */
137
        @SuppressWarnings("checkstyle:ParameterNumber")
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) {
3✔
155
                this.databasePath = databasePath;
3✔
156
                this.wait = wait;
3✔
157
                this.pause = pause;
3✔
158
                this.workingDirectory = workingDirectory;
3✔
159
                this.allocator = allocator;
3✔
160
                this.auth = auth;
3✔
161
                this.compat = compat;
3✔
162
                this.historicalData = historicalData;
3✔
163
                this.keepalive = keepalive;
3✔
164
                this.proxy = proxy;
3✔
165
                this.quota = quota;
3✔
166
                this.sqlite = sqlite;
3✔
167
                this.reportEmail = reportEmail;
3✔
168
                this.transceiver = transceiver;
3✔
169
                this.stateCtrl = stateControl;
3✔
170
                this.datasource = datasource;
3✔
171
        }
3✔
172

173
        /**
174
         * Path to the main database file.
175
         *
176
         * @return Path.
177
         */
178
        @NotNull
179
        public File getDatabasePath() {
180
                return databasePath;
3✔
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();
3✔
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;
3✔
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;
3✔
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;
3✔
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();
3✔
241
        }
242

243
        /**
244
         * @return Properties relating to historical data management.
245
         */
246
        @NotNull
247
        @Valid
248
        public HistoricalDataProperties getHistoricalData() {
249
                return historicalData;
3✔
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;
3✔
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;
3✔
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;
3✔
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;
3✔
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;
3✔
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;
3✔
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;
3✔
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;
3✔
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;
3✔
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;
3✔
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;
3✔
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
                public HistoricalDataProperties(
434
                                @DefaultValue("spalloc-history.sqlite3") File path,
435
                                @DefaultValue("14d") Duration gracePeriod,
436
                                @DefaultValue("0 0 2 * * *") String schedule,
437
                                @DefaultValue DataSourceProperties datasource) {
3✔
438
                        this.path = path;
3✔
439
                        this.gracePeriod = gracePeriod;
3✔
440
                        this.schedule = schedule;
3✔
441
                        this.datasource = datasource;
3✔
442
                }
3✔
443

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

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

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

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

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

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

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

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

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

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

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

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

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

537
                void setExpiryPeriod(Duration expiryPeriod) {
538
                        this.expiryPeriod = expiryPeriod;
×
539
                }
×
540

541
                /** @return Minimum keepalive period. */
542
                @NotNull
543
                public Duration getMin() {
544
                        return min;
3✔
545
                }
546

547
                void setMin(Duration min) {
548
                        this.min = min;
×
549
                }
×
550

551
                /** @return Maximum keepalive period. */
552
                @NotNull
553
                public Duration getMax() {
554
                        return max;
3✔
555
                }
556

557
                void setMax(Duration max) {
558
                        this.max = max;
×
559
                }
×
560

561
                @Keep
562
                @AssertTrue(message = "max must be more than min")
563
                private boolean isMaxMoreThanMin() {
564
                        return max.compareTo(min) > 0;
3✔
565
                }
566
        }
567

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

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

581
                /** Properties relating to job priority scaling. */
582
                private PriorityScale priorityScale;
583

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

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

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

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

626
                /**
627
                 * Time between runs of the main allocation algorithm.
628
                 *
629
                 * @return Time between runs of the main allocation algorithm.
630
                 */
631
                @NotNull
632
                public Duration getPeriod() {
633
                        return period;
3✔
634
                }
635

636
                void setPeriod(Duration period) {
637
                        this.period = period;
×
638
                }
×
639

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

652
                void setImportanceSpan(int importanceSpan) {
653
                        this.importanceSpan = importanceSpan;
×
654
                }
×
655

656
                /**
657
                 * Properties relating to job priority scaling.
658
                 *
659
                 * @return Properties relating to job priority scaling.
660
                 */
661
                @NotNull
662
                @Valid
663
                public PriorityScale getPriorityScale() {
664
                        return priorityScale;
3✔
665
                }
666

667
                void setPriorityScale(PriorityScale priorityScale) {
668
                        this.priorityScale = priorityScale;
×
669
                }
×
670

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

680
                void setReportActionThreshold(int threshold) {
681
                        reportActionThreshold = threshold;
×
682
                }
×
683

684
                /** @return Name of user that system-generated reports are done by. */
685
                @NotNull
686
                public String getSystemReportUser() {
687
                        return systemReportUser;
3✔
688
                }
689

690
                void setSystemReportUser(String systemReportUser) {
691
                        this.systemReportUser = systemReportUser;
×
692
                }
×
693

694
                /**
695
                 * @return Command code to accept for an emergency stop.
696
                 */
697
                @NotBlank
698
                public String getEmergencyStopCommandCode() {
699
                        return emergencyStopCommandCode;
3✔
700
                }
701

702
                void setEmergencyStopCommandCode(String emergencyStopCommandCode) {
NEW
703
                        this.emergencyStopCommandCode = emergencyStopCommandCode;
×
NEW
704
                }
×
705
        }
706

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

715
                /** Priority scaling factor for jobs given by rectangular dimensions. */
716
                private double dimensions;
717

718
                /** Priority scaling factor for jobs requiring a specific board. */
719
                private double specificBoard;
720

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

740
                /**
741
                 * @return Priority scaling factor for jobs given by number of boards.
742
                 */
743
                @Positive
744
                public double getSize() {
745
                        return size;
3✔
746
                }
747

748
                void setSize(double factor) {
749
                        size = factor;
×
750
                }
×
751

752
                /**
753
                 * @return Priority scaling factor for jobs given by rectangular
754
                 *         dimensions.
755
                 */
756
                @Positive
757
                public double getDimensions() {
758
                        return dimensions;
3✔
759
                }
760

761
                void setDimensions(double factor) {
762
                        dimensions = factor;
×
763
                }
×
764

765
                /**
766
                 * @return Priority scaling factor for jobs requiring a specific board.
767
                 */
768
                @Positive
769
                public double getSpecificBoard() {
770
                        return specificBoard;
3✔
771
                }
772

773
                void setSpecificBoard(double factor) {
774
                        specificBoard = factor;
×
775
                }
×
776
        }
777

778
        /** Notify an administrator about problems reported with boards. */
779
        public static class ReportProperties {
780
                private static final String DEFAULT_SUBJECT =
781
                                "NOTICE: Board taken out of service";
782

783
                /** Whether to send an email about reported boards. */
784
                private boolean send;
785

786
                /** The {@code From:} email address. */
787
                private String from;
788

789
                /** The {@code To:} email address. */
790
                private String to;
791

792
                /** The {@code Subject:} header. */
793
                private String subject;
794

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

815
                /** @return Whether to send an email about reported boards. */
816
                public boolean isSend() {
817
                        return send;
3✔
818
                }
819

820
                void setSend(boolean send) {
821
                        this.send = send;
×
822
                }
×
823

824
                /** @return The {@code From:} email address. */
825
                @Email
826
                public String getFrom() {
827
                        return from;
3✔
828
                }
829

830
                void setFrom(String address) {
831
                        from = address;
×
832
                }
×
833

834
                /** @return The {@code To:} email address. */
835
                @Email
836
                public String getTo() {
837
                        return to;
3✔
838
                }
839

840
                void setTo(String address) {
841
                        to = address;
×
842
                }
×
843

844
                /** @return The {@code Subject:} header. */
845
                @NotBlank
846
                public String getSubject() {
847
                        return subject;
3✔
848
                }
849

850
                void setSubject(String subject) {
851
                        this.subject = subject;
×
852
                }
×
853

854
                @Keep
855
                @AssertTrue(
856
                                message = "must supply from, to, and subject if send enabled")
857
                private boolean fieldsIfEnabled() {
858
                        return !send || (nonNull(from) && nonNull(to) && nonNull(subject));
×
859
                }
860
        }
861

862
        /** Authentication and authorization configuration. */
863
        public static class AuthProperties {
864
                /**
865
                 * Whether to enable HTTP BASIC authentication. Useful for simple
866
                 * clients.
867
                 */
868
                private boolean basic;
869

870
                /**
871
                 * The authentication realm. Must not contain quote characters!
872
                 */
873
                private String realm;
874

875
                /**
876
                 * Whether to enable HTTP form+session authentication. Much faster than
877
                 * BASIC, but requires a more complex client. You must enable this if
878
                 * you are supporting the Web UI.
879
                 */
880
                private boolean localForm;
881

882
                /**
883
                 * Force a known local admin user to exist with a known (by default)
884
                 * password.
885
                 */
886
                private boolean addDummyUser;
887

888
                /**
889
                 * Whether to generate a random password for the above user. If so, the
890
                 * password will be written to the log.
891
                 */
892
                private boolean dummyRandomPass;
893

894
                /**
895
                 * The name of the system default group. Only made if the
896
                 * {@linkplain #addDummyUser dummy user} is made.
897
                 */
898
                private String systemGroup;
899

900
                /** Provide extra information to callers on auth failures. */
901
                private boolean debugFailures;
902

903
                /** Number of login failures before automatic lock-out. */
904
                private int maxLoginFailures;
905

906
                /** Length of time that automatic lock-out lasts. */
907
                private Duration accountLockDuration;
908

909
                /**
910
                 * How often do we look for users to end their lock-out?
911
                 */
912
                private Duration unlockPeriod;
913

914
                /**
915
                 * OpenID-related security properties. Required for allowing people to
916
                 * use HBP/EBRAINS identities.
917
                 */
918
                private OpenIDProperties openid;
919

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

977
                /**
978
                 * Whether to enable HTTP BASIC authentication. Useful for simple
979
                 * clients; not great with browsers.
980
                 *
981
                 * @return Whether to enable HTTP BASIC authentication.
982
                 */
983
                public boolean isBasic() {
984
                        return basic;
3✔
985
                }
986

987
                void setBasic(boolean basic) {
988
                        this.basic = basic;
×
989
                }
×
990

991
                /**
992
                 * The authentication realm. Must not contain quote characters!
993
                 *
994
                 * @return the realm.
995
                 */
996
                @NotNull
997
                public String getRealm() {
998
                        return realm;
3✔
999
                }
1000

1001
                void setRealm(String realm) {
1002
                        this.realm = realm;
×
1003
                }
×
1004

1005
                /**
1006
                 * Whether to enable HTTP form+session authentication. Much faster than
1007
                 * BASIC, but requires a more complex client. You must enable this if
1008
                 * you are supporting the Web UI.
1009
                 *
1010
                 * @return Whether to enable HTTP form+session authentication.
1011
                 */
1012
                public boolean isLocalForm() {
1013
                        return localForm;
3✔
1014
                }
1015

1016
                void setLocalForm(boolean localForm) {
1017
                        this.localForm = localForm;
×
1018
                }
×
1019

1020
                /**
1021
                 * @return Force a known local admin user to exist with a known
1022
                 *         password.
1023
                 */
1024
                public boolean isAddDummyUser() {
1025
                        return addDummyUser;
3✔
1026
                }
1027

1028
                void setAddDummyUser(boolean addDummyUser) {
1029
                        this.addDummyUser = addDummyUser;
×
1030
                }
×
1031

1032
                /**
1033
                 * Whether to generate a random password for the default admin user. If
1034
                 * so, the password will be written to the log.
1035
                 *
1036
                 * @return Whether to generate a random password for the default admin
1037
                 *         user.
1038
                 */
1039
                public boolean isDummyRandomPass() {
1040
                        return dummyRandomPass;
×
1041
                }
1042

1043
                void setDummyRandomPass(boolean dummyRandomPass) {
1044
                        this.dummyRandomPass = dummyRandomPass;
×
1045
                }
×
1046

1047
                /**
1048
                 * The name of the system default group, that is internal and has no
1049
                 * quota (initially). Only made if the {@linkplain #addDummyUser dummy
1050
                 * user} is made.
1051
                 *
1052
                 * @return the name of the system group
1053
                 */
1054
                public String getSystemGroup() {
1055
                        return systemGroup;
3✔
1056
                }
1057

1058
                void setSystemGroup(String systemGroup) {
1059
                        this.systemGroup = systemGroup;
×
1060
                }
×
1061

1062
                /** @return Provide extra information to callers on auth failures. */
1063
                public boolean isDebugFailures() {
1064
                        return debugFailures;
×
1065
                }
1066

1067
                void setDebugFailures(boolean debugFailures) {
1068
                        this.debugFailures = debugFailures;
×
1069
                }
×
1070

1071
                /** @return Number of login failures before automatic lock-out. */
1072
                @Positive
1073
                public int getMaxLoginFailures() {
1074
                        return maxLoginFailures;
3✔
1075
                }
1076

1077
                void setMaxLoginFailures(int maxLoginFailures) {
1078
                        this.maxLoginFailures = maxLoginFailures;
×
1079
                }
×
1080

1081
                /** @return Length of time that automatic lock-out lasts. */
1082
                @NotNull
1083
                public Duration getAccountLockDuration() {
1084
                        return accountLockDuration;
3✔
1085
                }
1086

1087
                void setAccountLockDuration(Duration accountLockDuration) {
1088
                        this.accountLockDuration = accountLockDuration;
×
1089
                }
×
1090

1091
                /**
1092
                 * How often do we look for users to end their lock-out?
1093
                 *
1094
                 * @return How often do we look for users to end their lock-out?
1095
                 */
1096
                @NotNull
1097
                public Duration getUnlockPeriod() {
1098
                        return unlockPeriod;
3✔
1099
                }
1100

1101
                void setUnlockPeriod(Duration unlockPeriod) {
1102
                        this.unlockPeriod = unlockPeriod;
×
1103
                }
×
1104

1105
                /**
1106
                 * OpenID-related security properties. Required for allowing people to
1107
                 * use HBP/EBRAINS identities.
1108
                 *
1109
                 * @return OpenID-related security properties.
1110
                 */
1111
                @NotNull
1112
                @Valid
1113
                public OpenIDProperties getOpenid() {
1114
                        return openid;
3✔
1115
                }
1116

1117
                void setOpenid(OpenIDProperties openid) {
1118
                        this.openid = openid;
3✔
1119
                }
3✔
1120
        }
1121

1122
        /**
1123
         * OpenID-related security properties. Required for allowing people to use
1124
         * HBP/EBRAINS identities.
1125
         */
1126
        public static class OpenIDProperties {
1127
                /**
1128
                 * Whether to enable OIDC authentication. Required for allowing people
1129
                 * to use HBP/EBRAINS identities.
1130
                 */
1131
                private boolean enable;
1132

1133
                /**
1134
                 * The scopes desired. Referred to elsewhere in the configuration file.
1135
                 */
1136
                private Set<String> scopes;
1137

1138
                /** The ID of the registration of the client. */
1139
                private String registrationId;
1140

1141
                /**
1142
                 * The application installation identity. Required for allowing people
1143
                 * to use HBP/EBRAINS identities.
1144
                 */
1145
                private String id;
1146

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

1153
                /** Location of the OpenID Opaque Token Introspection service. */
1154
                private String introspection;
1155

1156
                /** Location of the OpenID User Info service. */
1157
                private String userinfo;
1158

1159
                /** Location of the authorization end-point. */
1160
                private String auth;
1161

1162
                /** Location of the token end-point. */
1163
                private String token;
1164

1165
                /** Location of the JWKS. */
1166
                private String jwkSet;
1167

1168
                /** Location of the issuer. */
1169
                private String issuer;
1170

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

1174
                private AuthorizationGrantType authGrantType;
1175

1176
                /** Prefix for user names originating from OpenID auto-registration. */
1177
                private String usernamePrefix;
1178

1179
                /** What kind of truststore is it. */
1180
                private String truststoreType;
1181

1182
                /** Where the truststore is. */
1183
                private Resource truststorePath;
1184

1185
                /** How to unlock the truststore. */
1186
                private String truststorePassword;
1187

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

1271
                /**
1272
                 * Whether to enable OIDC authentication. Required for allowing people
1273
                 * to use HBP/EBRAINS identities.
1274
                 *
1275
                 * @return Whether to enable OIDC authentication.
1276
                 */
1277
                public boolean isEnable() {
1278
                        return enable;
3✔
1279
                }
1280

1281
                void setEnable(boolean enable) {
1282
                        this.enable = enable;
×
1283
                }
×
1284

1285
                /**
1286
                 * The registration ID of the client.
1287
                 * @return The registration ID.
1288
                 */
1289
                public String getRegistrationId() {
1290
                        return registrationId;
×
1291
                }
1292

1293
                /**
1294
                 * The application installation identity. Required for allowing people
1295
                 * to use HBP/EBRAINS identities.
1296
                 *
1297
                 * @return The application installation identity.
1298
                 */
1299
                public String getId() {
1300
                        return id == null ? null : id.strip();
×
1301
                }
1302

1303
                void setId(String id) {
1304
                        this.id = id;
×
1305
                }
×
1306

1307
                /**
1308
                 * The application installation secret. Required for allowing people to
1309
                 * use HBP/EBRAINS identities.
1310
                 *
1311
                 * @return The application installation secret.
1312
                 */
1313
                public String getSecret() {
1314
                        return secret == null ? null : secret.strip();
×
1315
                }
1316

1317
                void setSecret(String secret) {
1318
                        this.secret = secret;
×
1319
                }
×
1320

1321
                /**
1322
                 * Location of the OpenID Opaque Token Introspection service.
1323
                 *
1324
                 * @return The Introspection location.
1325
                 */
1326
                public String getIntrospection() {
1327
                        return introspection;
×
1328
                }
1329

1330
                /**
1331
                 * Location of the OpenID User Information service.
1332
                 *
1333
                 * @return The Userinfo location.
1334
                 */
1335
                public String getUserinfo() {
1336
                        return userinfo;
×
1337
                }
1338

1339
                /**
1340
                 * Prefix for user names originating from OpenID auto-registration. Not
1341
                 * a good idea to modify this frequently!
1342
                 *
1343
                 * @return Prefix for user names originating from OpenID
1344
                 *         auto-registration.
1345
                 */
1346
                @NotNull
1347
                public String getUsernamePrefix() {
1348
                        return usernamePrefix;
3✔
1349
                }
1350

1351
                void setUsernamePrefix(String usernamePrefix) {
1352
                        this.usernamePrefix = usernamePrefix;
×
1353
                }
×
1354

1355
                /**
1356
                 * The scopes desired. Referred to elsewhere in the configuration file.
1357
                 *
1358
                 * @return The OpenID scopes.
1359
                 */
1360
                @NotEmpty
1361
                public Set<String> getScopes() {
1362
                        return scopes;
3✔
1363
                }
1364

1365
                void setScopes(Set<String> scopes) {
1366
                        this.scopes = scopes;
3✔
1367
                }
3✔
1368

1369
                /**
1370
                 * What kind of truststore is it.
1371
                 *
1372
                 * @return truststore type (default: {@code PKCS12})
1373
                 */
1374
                @NotNull
1375
                public String getTruststoreType() {
1376
                        return truststoreType;
3✔
1377
                }
1378

1379
                void setTruststoreType(String truststoreType) {
1380
                        this.truststoreType = truststoreType;
×
1381
                }
×
1382

1383
                /**
1384
                 * Where the truststore is.
1385
                 *
1386
                 * @return truststore location
1387
                 */
1388
                @NotNull
1389
                public Resource getTruststorePath() {
1390
                        return truststorePath;
3✔
1391
                }
1392

1393
                void setTruststorePath(Resource truststorePath) {
1394
                        this.truststorePath = truststorePath;
×
1395
                }
×
1396

1397
                /**
1398
                 * How to unlock the truststore. This is not considered to be actually
1399
                 * secret, but rather just a technical requirement of the truststore
1400
                 * format.
1401
                 *
1402
                 * @return password for truststore
1403
                 */
1404
                @NotNull
1405
                public String getTruststorePassword() {
1406
                        return truststorePassword;
3✔
1407
                }
1408

1409
                void setTruststorePassword(String truststorePassword) {
1410
                        this.truststorePassword = truststorePassword;
×
1411
                }
×
1412

1413
                /**
1414
                 * @return the OIDC Authorization End-point URL.
1415
                 */
1416
                public String getAuth() {
1417
                        return auth;
×
1418
                }
1419

1420
                void setAuth(String auth) {
1421
                        this.auth = auth;
×
1422
                }
×
1423

1424
                /**
1425
                 * @return the OIDC Token End-point URL.
1426
                 */
1427
                public String getToken() {
1428
                        return token;
×
1429
                }
1430

1431
                void setToken(String token) {
1432
                        this.token = token;
×
1433
                }
×
1434

1435
                /**
1436
                 * @return the OIDC JWK Set URL.
1437
                 */
1438
                public String getJwkSet() {
1439
                        return jwkSet;
×
1440
                }
1441

1442
                void setJwkSet(String jwkSet) {
1443
                        this.jwkSet = jwkSet;
×
1444
                }
×
1445

1446
                /**
1447
                 * @return The OIDC issuer URL.
1448
                 */
1449
                public String getIssuer() {
1450
                        return issuer;
×
1451
                }
1452

1453
                void setIssuer(String issuer) {
1454
                        this.issuer = issuer;
×
1455
                }
×
1456

1457
                /**
1458
                 * @return the redirect URL to return to.
1459
                 */
1460
                public String getRedirect() {
1461
                        return redirect;
×
1462
                }
1463

1464
                void setRedirect(String redirect) {
1465
                        this.redirect = redirect;
×
1466
                }
×
1467

1468
                /**
1469
                 * @return the OIDC Authorization grant type.
1470
                 */
1471
                public AuthorizationGrantType getAuthGrantType() {
1472
                        return authGrantType;
×
1473
                }
1474

1475
                void setAuthGrantType(AuthorizationGrantType authGrantType) {
1476
                        this.authGrantType = authGrantType;
×
1477
                }
×
1478

1479
                /**
1480
                 * @param introspection the OIDC introspection URL.
1481
                 */
1482
                void setIntrospection(String introspection) {
1483
                        this.introspection = introspection;
×
1484
                }
×
1485

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

1493
                @Keep
1494
                @AssertTrue(
1495
                                message = "id and secret must be given if OpenID is enabled")
1496
                private boolean isValid() {
1497
                        return !enable || (nonNull(id) && !id.isBlank()
3✔
1498
                                        && nonNull(secret) && !secret.isBlank());
3✔
1499
                }
1500
        }
1501

1502
        /** Quota management. */
1503
        public static class QuotaProperties {
1504
                /** Default user quota in board-seconds. */
1505
                private int defaultQuota;
1506

1507
                /**
1508
                 * Default quota for organisations inflated from OpenID, in
1509
                 * board-seconds.
1510
                 */
1511
                private long orgQuota;
1512

1513
                /**
1514
                 * Default quota for collabratories inflated from OpenID, in
1515
                 * board-seconds.
1516
                 */
1517
                private long collabQuota;
1518

1519
                /**
1520
                 * Cron expression that says when we consolidate job quotas into the
1521
                 * main quota table.
1522
                 */
1523
                private String consolidationSchedule;
1524

1525
                /**
1526
                 * The URL of the NMPI service which maintains quotas.
1527
                 */
1528
                private String nmpiUrl;
1529

1530
                /**
1531
                 * The API Key to use to access the NMPI service.
1532
                 */
1533
                private String nmpiApiKey;
1534

1535
                /**
1536
                 * The name of the platform to use to read quota.
1537
                 */
1538
                private String nmpiPlatform;
1539

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

1576
                /**
1577
                 * Default user quota in board-seconds.
1578
                 *
1579
                 * @return Default user quota in board-seconds.
1580
                 */
1581
                @PositiveOrZero
1582
                public int getDefaultQuota() {
1583
                        return defaultQuota;
3✔
1584
                }
1585

1586
                void setDefaultQuota(int defaultQuota) {
1587
                        this.defaultQuota = defaultQuota;
×
1588
                }
×
1589

1590
                /**
1591
                 * Default quota for organisations.
1592
                 *
1593
                 * @return Default quota for organisations inflated from OpenID, in
1594
                 *         board-seconds.
1595
                 */
1596
                public long getDefaultOrgQuota() {
1597
                        return orgQuota;
×
1598
                }
1599

1600
                void setDefaultOrgQuota(long orgQuota) {
1601
                        this.orgQuota = orgQuota;
×
1602
                }
×
1603

1604
                /**
1605
                 * Default quota for collabratories.
1606
                 *
1607
                 * @return Default quota for collabratories inflated from OpenID, in
1608
                 *         board-seconds.
1609
                 */
1610
                public long getDefaultCollabQuota() {
1611
                        return collabQuota;
×
1612
                }
1613

1614
                void setDefaultCollabQuota(long collabQuota) {
1615
                        this.collabQuota = collabQuota;
×
1616
                }
×
1617

1618
                /**
1619
                 * @return Cron expression that says when we consolidate job quotas into
1620
                 *         the main quota table.
1621
                 */
1622
                @NotBlank
1623
                public String getConsolidationSchedule() {
1624
                        return consolidationSchedule;
3✔
1625
                }
1626

1627
                void setConsolidationSchedule(String consolidationSchedule) {
1628
                        this.consolidationSchedule = consolidationSchedule;
×
1629
                }
×
1630

1631
                /**
1632
                 * @return The URL of an NMPI server that deals with quota.
1633
                 *         May be blank, meaning there isn't one.
1634
                 */
1635
                public String getNMPIUrl() {
1636
                        return nmpiUrl;
3✔
1637
                }
1638

1639
                void setNMPIUrl(String nmpiUrl) {
1640
                        this.nmpiUrl = nmpiUrl;
×
1641
                }
×
1642

1643
                /**
1644
                 * @return The API Key to use to access the NMPI server.
1645
                 *         May be blank if @linkplain(#nmpiUrl) is blank.
1646
                 */
1647
                public String getNMPIApiKey() {
1648
                        return nmpiApiKey;
×
1649
                }
1650

1651
                void setNMPIApiKey(String nmpiApiKey) {
1652
                        this.nmpiApiKey = nmpiApiKey;
×
1653
                }
×
1654

1655
                /**
1656
                 * @return The platform to look for on the NMPI server.
1657
                 */
1658
                public String getNMPIPlaform() {
1659
                        return nmpiPlatform;
×
1660
                }
1661

1662
                void setNMPIPlatform(String nmpiPlatform) {
1663
                        this.nmpiPlatform = nmpiPlatform;
×
1664
                }
×
1665
        }
1666

1667
        /** Controls how Spalloc talks to BMPs on machines. */
1668
        public static class TxrxProperties {
1669
                /**
1670
                 * How long between when we send requests to the BMP control tasks.
1671
                 */
1672
                private Duration period;
1673

1674
                /** The basic wait time used by the BMP control tasks. */
1675
                private Duration probeInterval;
1676

1677
                /** Number of attempts that will be made to switch on a board. */
1678
                private int powerAttempts;
1679

1680
                /** Number of attempts that will be made to bring up an FPGA. */
1681
                private int fpgaAttempts;
1682

1683
                /**
1684
                 * Whether to reload the FPGA bitfiles when they don't come up
1685
                 * correctly.
1686
                 */
1687
                private boolean fpgaReload;
1688

1689
                /**
1690
                 * Number of attempts that will be made to bring up a transceiver,
1691
                 * provided the failures are due to timeouts and not outright network
1692
                 * errors. Note that a failure to bring up a transceiver is lethal to
1693
                 * the service.
1694
                 */
1695
                private int buildAttempts;
1696

1697
                /** Whether to use a dummy transceiver. Useful for testing only. */
1698
                private boolean dummy;
1699

1700
                /** The time a board has to be off before it can be powered on. */
1701
                private Duration offWaitTime;
1702

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

1746
                /**
1747
                 * How long between when we send requests to the BMP control tasks.
1748
                 *
1749
                 * @return How long between when we send requests to the BMP control
1750
                 *         tasks.
1751
                 */
1752
                @NotNull
1753
                public Duration getPeriod() {
1754
                        return period;
3✔
1755
                }
1756

1757
                void setPeriod(Duration period) {
1758
                        this.period = period;
×
1759
                }
×
1760

1761
                /** @return The basic wait time used by the BMP control tasks. */
1762
                @NotNull
1763
                public Duration getProbeInterval() {
1764
                        return probeInterval;
3✔
1765
                }
1766

1767
                @NotNull
1768
                public Duration getOffWaitTime() {
1769
                        return offWaitTime;
3✔
1770
                }
1771

1772
                void setProbeInterval(Duration probeInterval) {
1773
                        this.probeInterval = probeInterval;
×
1774
                }
×
1775

1776
                /**
1777
                 * @return Number of attempts that will be made to switch on a board.
1778
                 */
1779
                @Positive
1780
                public int getPowerAttempts() {
1781
                        return powerAttempts;
3✔
1782
                }
1783

1784
                void setPowerAttempts(int powerAttempts) {
1785
                        this.powerAttempts = powerAttempts;
×
1786
                }
×
1787

1788
                /** @return Number of attempts that will be made to bring up an FPGA. */
1789
                @Positive
1790
                public int getFpgaAttempts() {
1791
                        return fpgaAttempts;
3✔
1792
                }
1793

1794
                void setFpgaAttempts(int fpgaAttempts) {
1795
                        this.fpgaAttempts = fpgaAttempts;
×
1796
                }
×
1797

1798
                /**
1799
                 * @return Whether to reload the FPGA bitfiles when they don't come up
1800
                 *         correctly.
1801
                 */
1802
                public boolean isFpgaReload() {
UNCOV
1803
                        return fpgaReload;
×
1804
                }
1805

1806
                void setFpgaReload(boolean fpgaReload) {
1807
                        this.fpgaReload = fpgaReload;
×
1808
                }
×
1809

1810
                /**
1811
                 * Number of attempts that will be made to bring up a transceiver,
1812
                 * provided the failures are due to timeouts and not outright network
1813
                 * errors. Note that a failure to bring up a transceiver is lethal to
1814
                 * the service.
1815
                 *
1816
                 * @return Number of attempts that will be made to bring up a
1817
                 *         transceiver.
1818
                 */
1819
                @Positive
1820
                public int getBuildAttempts() {
1821
                        return buildAttempts;
3✔
1822
                }
1823

1824
                void setBuildAttempts(int value) {
1825
                        this.buildAttempts = value;
×
1826
                }
×
1827

1828
                /**
1829
                 * Useful for testing only.
1830
                 *
1831
                 * @return Whether to use a dummy transceiver.
1832
                 */
1833
                public boolean isDummy() {
1834
                        return dummy;
3✔
1835
                }
1836

1837
                void setDummy(boolean dummy) {
1838
                        this.dummy = dummy;
×
1839
                }
×
1840
        }
1841

1842
        /**
1843
         * The properties of a {@link DataSource}, describing how to make a database
1844
         * connection.
1845
         */
1846
        @UsedInJavadocOnly(DataSource.class)
1847
        public static class DataSourceProperties {
1848
                /** URL for creating a connection. */
1849
                @NotEmpty
1850
                private String jdbcUrl;
1851

1852
                /** User name for the connection. */
1853
                private String username;
1854

1855
                /** Password for the connection. */
1856
                private String password;
1857

1858
                /**
1859
                 * @param jdbcUrl
1860
                 *            URL for creating a connection.
1861
                 * @param username
1862
                 *            User name for the connection.
1863
                 * @param password
1864
                 *            Password for the connection.
1865
                 */
1866
                public DataSourceProperties(
1867
                                @DefaultValue("jdbc:sqlite:/fix.me") String jdbcUrl,
1868
                                @DefaultValue("sa") String username,
1869
                                @DefaultValue("*") String password) {
3✔
1870
                        this.jdbcUrl = jdbcUrl;
3✔
1871
                        this.username = username;
3✔
1872
                        this.password = password;
3✔
1873
                }
3✔
1874

1875
                /** @return URL for creating a connection. */
1876
                public String getJdbcUrl() {
1877
                        return jdbcUrl;
×
1878
                }
1879

1880
                void setJdbcUrl(String jdbcUrl) {
1881
                        this.jdbcUrl = jdbcUrl;
×
1882
                }
×
1883

1884
                /** @return User name for the connection. */
1885
                public String getUsername() {
1886
                        return username;
×
1887
                }
1888

1889
                void setUsername(String username) {
1890
                        this.username = username;
×
1891
                }
×
1892

1893
                /** @return Password for the connection. */
1894
                public String getPassword() {
1895
                        return password;
×
1896
                }
1897

1898
                void setPassword(String password) {
1899
                        this.password = password;
×
1900
                }
×
1901
        }
1902

1903
        /** Additional database configuration. */
1904
        public static class DBProperties {
1905
                private static final int MAX_ANALYSIS = 1000;
1906

1907
                private static final int MIN_ANALYSIS = 100;
1908

1909
                /** How long to wait to get a database lock. */
1910
                private Duration timeout;
1911

1912
                /** Whether to send details of SQL-related exceptions to users. */
1913
                private boolean debugFailures;
1914

1915
                /**
1916
                 * Amount of effort to spend on DB optimisation on application close.
1917
                 * See the SQLite documentation for meaning. Note that this is spent by
1918
                 * every worker thread that touches the database.
1919
                 */
1920
                private int analysisLimit;
1921

1922
                /**
1923
                 * Whether to collect and write query performance metrics to the log on
1924
                 * termination.
1925
                 */
1926
                private boolean performanceLog;
1927

1928
                /**
1929
                 * If the performance log is enabled, also write the EXPLAIN of the code
1930
                 * to the log on termination (for slow queries only).
1931
                 */
1932
                private boolean autoExplain;
1933

1934
                /**
1935
                 * Performance stats not reported for queries with a max less than this
1936
                 * (in &mu;s).
1937
                 */
1938
                private double performanceThreshold;
1939

1940
                /** Number of times to try to take the lock in a transaction. */
1941
                private int lockTries;
1942

1943
                /** Delay after transaction failure before retrying. */
1944
                private Duration lockFailedDelay;
1945

1946
                /** Time delay before we issue a warning on transaction end. */
1947
                private Duration lockNoteThreshold;
1948

1949
                /**
1950
                 * Time delay before we issue a warning during the execution of a
1951
                 * transaction.
1952
                 */
1953
                private Duration lockWarnThreshold;
1954

1955
                /** Whether to determine the caller when doing transaction logging. */
1956
                private boolean enableExpensiveTransactionDebugging;
1957

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

2018
                /** @return How long to wait to get a database lock. */
2019
                @NotNull
2020
                public Duration getTimeout() {
2021
                        return timeout;
3✔
2022
                }
2023

2024
                void setTimeout(Duration timeout) {
2025
                        this.timeout = timeout;
×
2026
                }
×
2027

2028
                /**
2029
                 * @return Whether to send details of SQL-related exceptions to users.
2030
                 */
2031
                public boolean isDebugFailures() {
2032
                        return debugFailures;
×
2033
                }
2034

2035
                void setDebugFailures(boolean debugFailures) {
2036
                        this.debugFailures = debugFailures;
×
2037
                }
×
2038

2039
                /**
2040
                 * Amount of effort to spend on DB optimisation on application close.
2041
                 * See the SQLite documentation for meaning. Note that this is spent by
2042
                 * every worker thread that touches the database.
2043
                 *
2044
                 * @return Amount of effort to spend on DB optimisation on application
2045
                 *         close.
2046
                 * @see <a href="https://sqlite.org/lang_analyze.html">SQLite docs</a>
2047
                 */
2048
                @Min(MIN_ANALYSIS)
2049
                @Max(MAX_ANALYSIS)
2050
                public int getAnalysisLimit() {
2051
                        return analysisLimit;
3✔
2052
                }
2053

2054
                void setAnalysisLimit(int analysisLimit) {
2055
                        this.analysisLimit = analysisLimit;
×
2056
                }
×
2057

2058
                /**
2059
                 * @return Whether to collect and write query performance metrics to the
2060
                 *         log on termination. Note that this is checked both when
2061
                 *         recording performance (on each database query) and when the
2062
                 *         log writes happen (on termination).
2063
                 */
2064
                public final boolean isPerformanceLog() {
2065
                        return performanceLog;
×
2066
                }
2067

2068
                void setPerformanceLog(boolean log) {
2069
                        this.performanceLog = log;
×
2070
                }
×
2071

2072
                /**
2073
                 * @return Whether, if the performance log is enabled, to also write the
2074
                 *         EXPLAIN of the code to the log on termination (for slow
2075
                 *         queries only).
2076
                 */
2077
                public final boolean isAutoExplain() {
2078
                        return autoExplain;
×
2079
                }
2080

2081
                void setAutoExplain(boolean flag) {
2082
                        this.autoExplain = flag;
×
2083
                }
×
2084

2085
                /**
2086
                 * @return Performance stats are not reported for queries with a max
2087
                 *         less than this, in microseconds.
2088
                 */
2089
                @Positive
2090
                public final double getPerformanceThreshold() {
2091
                        return performanceThreshold;
3✔
2092
                }
2093

2094
                void setPerformanceThreshold(double threshold) {
2095
                        this.performanceThreshold = threshold;
×
2096
                }
×
2097

2098
                /** @return Number of times to try to take the lock in a transaction. */
2099
                @Positive
2100
                public int getLockTries() {
2101
                        return lockTries;
3✔
2102
                }
2103

2104
                void setLockTries(int lockTries) {
2105
                        this.lockTries = lockTries;
×
2106
                }
×
2107

2108
                /** @return Delay after transaction failure before retrying. */
2109
                @NotNull
2110
                public Duration getLockFailedDelay() {
2111
                        return lockFailedDelay;
3✔
2112
                }
2113

2114
                void setLockFailedDelay(Duration value) {
2115
                        this.lockFailedDelay = value;
×
2116
                }
×
2117

2118
                /** @return Time delay before we issue a warning on transaction end. */
2119
                @NotNull
2120
                public Duration getLockNoteThreshold() {
2121
                        return lockNoteThreshold;
3✔
2122
                }
2123

2124
                void setLockNoteThreshold(Duration value) {
2125
                        this.lockNoteThreshold = value;
×
2126
                }
×
2127

2128
                /**
2129
                 * @return Time delay before we issue a warning during the execution of
2130
                 *         a transaction.
2131
                 */
2132
                @NotNull
2133
                public Duration getLockWarnThreshold() {
2134
                        return lockWarnThreshold;
3✔
2135
                }
2136

2137
                void setLockWarnThreshold(Duration value) {
2138
                        this.lockWarnThreshold = value;
×
2139
                }
×
2140

2141
                /**
2142
                 * @return Whether to determine the caller when doing transaction
2143
                 *         logging.
2144
                 */
2145
                public boolean isEnableExpensiveTransactionDebugging() {
2146
                        return enableExpensiveTransactionDebugging;
×
2147
                }
2148

2149
                void setEnableExpensiveTransactionDebugging(boolean value) {
2150
                        this.enableExpensiveTransactionDebugging = value;
×
2151
                }
×
2152
        }
2153

2154
        /** Settings relating to the v1 spalloc configuration interface. */
2155
        public static class CompatibilityProperties {
2156
                /**
2157
                 * Whether to turn the spalloc version 1 compatibility service interface
2158
                 * on.
2159
                 */
2160
                private boolean enable;
2161

2162
                /**
2163
                 * The number of threads to use to service the v1 clients. 0 means no
2164
                 * limit.
2165
                 */
2166
                private int threadPoolSize;
2167

2168
                /** What hostname to run the spalloc v1 compatibility service on. */
2169
                private String host;
2170

2171
                /** What TCP port to run the spalloc v1 compatibility service on. */
2172
                private int port;
2173

2174
                /** How long to wait for the executor to shut down, maximum. */
2175
                private Duration shutdownTimeout;
2176

2177
                /**
2178
                 * How long to wait for a message to be received. Making this too short
2179
                 * makes the service more expensive. Making this too long makes the
2180
                 * service difficult to shut down correctly.
2181
                 */
2182
                private Duration receiveTimeout;
2183

2184
                /**
2185
                 * What user to run jobs submitted through the spalloc v1 compatibility
2186
                 * service with. We recommend that this user exists but is disabled
2187
                 * (i.e., login using this service identity need not be supported).
2188
                 */
2189
                private String serviceUser;
2190

2191
                /**
2192
                 * What group to run jobs submitted through the spalloc v1 compatibility
2193
                 * service against. This group needs to exist, and the service user
2194
                 * needs to be a member of it, but does not need to have a quota set.
2195
                 */
2196
                private String serviceGroup;
2197

2198
                /**
2199
                 * How long to pass to the spalloc core to wait for timeouts relating to
2200
                 * message notifications (i.e., due to machine or job status changes).
2201
                 */
2202
                private Duration notifyWaitTime;
2203

2204
                /** The default value for the keepalive property of jobs. */
2205
                private Duration defaultKeepalive;
2206

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

2266
                /**
2267
                 * @return Whether to turn the spalloc version 1 compatibility service
2268
                 *         interface on.
2269
                 */
2270
                public boolean isEnable() {
2271
                        return enable;
3✔
2272
                }
2273

2274
                void setEnable(boolean enable) {
2275
                        this.enable = enable;
×
2276
                }
×
2277

2278
                /**
2279
                 * @return The number of threads to use to service the v1 clients. 0
2280
                 *         means no limit (slightly dangerous).
2281
                 */
2282
                @PositiveOrZero
2283
                public int getThreadPoolSize() {
2284
                        return threadPoolSize;
3✔
2285
                }
2286

2287
                void setThreadPoolSize(int threadPoolSize) {
2288
                        this.threadPoolSize = threadPoolSize;
×
2289
                }
×
2290

2291
                /**
2292
                 * @return What host address to run the spalloc v1 compatibility service
2293
                 *         on.
2294
                 */
2295
                @NotBlank
2296
                public String getHost() {
2297
                        return host;
3✔
2298
                }
2299

2300
                void setHost(String host) {
2301
                        this.host = host;
×
2302
                }
×
2303

2304
                /**
2305
                 * @return What TCP port to run the spalloc v1 compatibility service on.
2306
                 */
2307
                @TCPPort(ephemeral = false)
2308
                public int getPort() {
2309
                        return port;
3✔
2310
                }
2311

2312
                void setPort(int port) {
2313
                        this.port = port;
×
2314
                }
×
2315

2316
                /**
2317
                 * What user to run jobs submitted through the spalloc v1 compatibility
2318
                 * service with. We recommend that this user exists but is disabled
2319
                 * (i.e., login using this service identity need not be supported).
2320
                 *
2321
                 * @return What user to run jobs submitted through the spalloc v1
2322
                 *         compatibility service with.
2323
                 */
2324
                public String getServiceUser() {
2325
                        return serviceUser;
3✔
2326
                }
2327

2328
                void setServiceUser(String serviceUser) {
2329
                        this.serviceUser = serviceUser;
×
2330
                }
×
2331

2332
                @Keep
2333
                @AssertTrue(message = "a service username must be given "
2334
                                + "if the v1 service is enabled")
2335
                private boolean isValidUserIfEnabled() {
2336
                        return !enable
3✔
2337
                                        || (nonNull(serviceUser) && !serviceUser.isBlank());
3✔
2338
                }
2339

2340
                /**
2341
                 * What group to run jobs submitted through the spalloc v1 compatibility
2342
                 * service against. This group needs to exist, and the service user
2343
                 * needs to be a member of it, but does not need to have a quota set.
2344
                 *
2345
                 * @return What group to run jobs submitted through the spalloc v1
2346
                 *         compatibility service against.
2347
                 */
2348
                public String getServiceGroup() {
2349
                        return serviceGroup;
3✔
2350
                }
2351

2352
                void setServiceGroup(String serviceUser) {
2353
                        this.serviceGroup = serviceUser;
×
2354
                }
×
2355

2356
                @Keep
2357
                @AssertTrue(message = "a service group must be given "
2358
                                + "if the v1 service is enabled")
2359
                private boolean isValidGroupIfEnabled() {
2360
                        return !enable || (nonNull(serviceGroup)
3✔
2361
                                        && !serviceGroup.isBlank());
3✔
2362
                }
2363

2364
                /**
2365
                 * @return How long to wait for the executor to shut down, maximum.
2366
                 */
2367
                @NotNull
2368
                public Duration getShutdownTimeout() {
2369
                        return shutdownTimeout;
3✔
2370
                }
2371

2372
                void setShutdownTimeout(Duration value) {
2373
                        this.shutdownTimeout = value;
×
2374
                }
×
2375

2376
                /**
2377
                 * Making this too short makes the service more expensive. Making this
2378
                 * too long makes the service difficult to shut down correctly. (Failure
2379
                 * to receive in this time triggers an exception, but it needs to be
2380
                 * fairly frequent or the thread can't be interrupted.)
2381
                 *
2382
                 * @return How long to wait for a message to be received.
2383
                 */
2384
                @NotNull
2385
                public Duration getReceiveTimeout() {
2386
                        return receiveTimeout;
3✔
2387
                }
2388

2389
                void setReceiveTimeout(Duration value) {
2390
                        this.receiveTimeout = value;
×
2391
                }
×
2392

2393
                /**
2394
                 * @return How long to pass to the spalloc core to wait for timeouts
2395
                 *         relating to message notifications (i.e., due to machine or
2396
                 *         job status changes).
2397
                 */
2398
                @NotNull
2399
                public Duration getNotifyWaitTime() {
2400
                        return notifyWaitTime;
3✔
2401
                }
2402

2403
                void setNotifyWaitTime(Duration value) {
2404
                        this.notifyWaitTime = value;
×
2405
                }
×
2406

2407
                /**
2408
                 * @return The default value for the keepalive property of jobs.
2409
                 */
2410
                @NotNull
2411
                public Duration getDefaultKeepalive() {
2412
                        return defaultKeepalive;
3✔
2413
                }
2414

2415
                void setDefaultKeepalive(Duration value) {
2416
                        this.defaultKeepalive = value;
×
2417
                }
×
2418
        }
2419

2420
        /** Settings for the proxies. */
2421
        public static class ProxyProperties {
2422
                /** Whether to enable the UDP proxy subsystem. */
2423
                private boolean enable;
2424

2425
                /**
2426
                 * Whether to log the number of packets read and written on each
2427
                 * channel.
2428
                 */
2429
                private boolean logWriteCounts;
2430

2431
                /**
2432
                 * The address for local proxied sockets to listen on if they're not
2433
                 * being bound to a specific board. If empty, that type of socket will
2434
                 * be disabled.
2435
                 */
2436
                private String localHost;
2437

2438
                /**
2439
                 * @param enable
2440
                 *            Whether to enable the UDP proxy subsystem.
2441
                 * @param logWriteCounts
2442
                 *            Whether to log the number of packets read and written on
2443
                 *            each channel.
2444
                 * @param localHost
2445
                 *            The address for local proxied sockets to listen on if
2446
                 *            they're not being bound to a specific board. If empty,
2447
                 *            that type of socket will be disabled.
2448
                 */
2449
                public ProxyProperties(@DefaultValue("true") boolean enable,
2450
                                @DefaultValue("false") boolean logWriteCounts,
2451
                                @DefaultValue("") String localHost) {
3✔
2452
                        this.enable = enable;
3✔
2453
                        this.logWriteCounts = logWriteCounts;
3✔
2454
                        this.localHost = localHost;
3✔
2455
                }
3✔
2456

2457
                /** @return Whether to enable the UDP proxy subsystem. */
2458
                public boolean isEnable() {
2459
                        return enable;
3✔
2460
                }
2461

2462
                void setEnable(boolean enable) {
2463
                        this.enable = enable;
×
2464
                }
×
2465

2466
                /**
2467
                 * @return Whether to log the number of packets read and written on each
2468
                 *         channel.
2469
                 */
2470
                public boolean isLogWriteCounts() {
2471
                        return logWriteCounts;
×
2472
                }
2473

2474
                void setLogWriteCounts(boolean logWriteCounts) {
2475
                        this.logWriteCounts = logWriteCounts;
×
2476
                }
×
2477

2478
                /**
2479
                 * @return The address for local proxied sockets to listen on if
2480
                 *         they're not being bound to a specific board. If empty, that
2481
                 *         type of socket will be disabled.
2482
                 */
2483
                @NotNull
2484
                @IPAddress(emptyOK = true)
2485
                public String getLocalHost() {
2486
                        return localHost;
3✔
2487
                }
2488

2489
                void setLocalHost(String localHost) {
2490
                        this.localHost = localHost;
×
2491
                }
×
2492
        }
2493

2494
        /** Settings for control of the administrative state of a machine. */
2495
        public static class StateControlProperties {
2496
                /** How long to wait between polls of the BMP controller. */
2497
                private Duration blacklistPoll;
2498

2499
                /** How long to wait for a blacklist operation to complete. */
2500
                private Duration blacklistTimeout;
2501

2502
                /**
2503
                 * How many board serial numbers to read from a full machine at once
2504
                 * when synchronizing the overall state?
2505
                 */
2506
                private int serialReadBatchSize;
2507

2508
                /**
2509
                 * How many blacklists to read from a full machine at once when
2510
                 * synchronizing the overall state?
2511
                 */
2512
                private int blacklistReadBatchSize;
2513

2514
                /**
2515
                 * @param blacklistPoll
2516
                 *            How long to wait between polls of the BMP controller.
2517
                 * @param blacklistTimeout
2518
                 *            How long to wait for a blacklist operation to complete.
2519
                 * @param serialReadBatchSize
2520
                 *            How many board serial numbers to read from a full machine
2521
                 *            at once when synchronizing the overall state?
2522
                 * @param blacklistReadBatchSize
2523
                 *            How many blacklists to read from a full machine at once
2524
                 *            when synchronizing the overall state?
2525
                 */
2526
                public StateControlProperties(
2527
                                @DefaultValue("15s") Duration blacklistPoll,
2528
                                @DefaultValue("60s") Duration blacklistTimeout,
2529
                                @DefaultValue("24") int serialReadBatchSize,
2530
                                @DefaultValue("6") int blacklistReadBatchSize) {
3✔
2531
                        this.blacklistPoll = blacklistPoll;
3✔
2532
                        this.blacklistTimeout = blacklistTimeout;
3✔
2533
                        this.serialReadBatchSize = serialReadBatchSize;
3✔
2534
                        this.blacklistReadBatchSize = blacklistReadBatchSize;
3✔
2535
                }
3✔
2536

2537
                /** @return How long to wait between polls of the BMP controller. */
2538
                @NotNull
2539
                public Duration getBlacklistPoll() {
2540
                        return blacklistPoll;
3✔
2541
                }
2542

2543
                void setBlacklistPoll(Duration blacklistPoll) {
2544
                        this.blacklistPoll = blacklistPoll;
×
2545
                }
×
2546

2547
                /** @return How long to wait for a blacklist operation to complete. */
2548
                @NotNull
2549
                public Duration getBlacklistTimeout() {
2550
                        return blacklistTimeout;
3✔
2551
                }
2552

2553
                void setBlacklistTimeout(Duration blacklistTimeout) {
2554
                        this.blacklistTimeout = blacklistTimeout;
×
2555
                }
×
2556

2557
                /**
2558
                 * @return How many board serial numbers to read from a full machine at
2559
                 *         once when synchronizing the overall state?
2560
                 */
2561
                @Positive
2562
                public int getSerialReadBatchSize() {
2563
                        return serialReadBatchSize;
3✔
2564
                }
2565

2566
                void setSerialReadBatchSize(int serialReadBatchSize) {
2567
                        this.serialReadBatchSize = serialReadBatchSize;
×
2568
                }
×
2569

2570
                /**
2571
                 * @return How many blacklists to read from a full machine at once when
2572
                 *         synchronizing the overall state?
2573
                 */
2574
                @Positive
2575
                public int getBlacklistReadBatchSize() {
2576
                        return blacklistReadBatchSize;
3✔
2577
                }
2578

2579
                void setBlacklistReadBatchSize(int blacklistReadBatchSize) {
2580
                        this.blacklistReadBatchSize = blacklistReadBatchSize;
×
2581
                }
×
2582
        }
2583
}
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