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

SpiNNakerManchester / JavaSpiNNaker / 6233274834

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

Pull #658

github

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

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

8373 of 22997 relevant lines covered (36.41%)

0.36 hits per line

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

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

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

20
import java.time.Duration;
21
import java.util.List;
22

23
import javax.validation.Valid;
24
import javax.validation.constraints.AssertFalse;
25
import javax.validation.constraints.AssertTrue;
26
import javax.validation.constraints.NotBlank;
27
import javax.validation.constraints.NotNull;
28
import javax.validation.constraints.Positive;
29
import javax.validation.constraints.PositiveOrZero;
30

31
import com.fasterxml.jackson.annotation.JsonIgnore;
32
import com.fasterxml.jackson.annotation.JsonProperty;
33
import com.google.errorprone.annotations.Keep;
34

35
import uk.ac.manchester.spinnaker.machine.board.ValidBoardNumber;
36
import uk.ac.manchester.spinnaker.machine.board.ValidCabinetNumber;
37
import uk.ac.manchester.spinnaker.machine.board.ValidFrameNumber;
38
import uk.ac.manchester.spinnaker.machine.board.ValidTriadHeight;
39
import uk.ac.manchester.spinnaker.machine.board.ValidTriadWidth;
40
import uk.ac.manchester.spinnaker.machine.board.ValidTriadX;
41
import uk.ac.manchester.spinnaker.machine.board.ValidTriadY;
42
import uk.ac.manchester.spinnaker.machine.board.ValidTriadZ;
43
import uk.ac.manchester.spinnaker.utils.validation.IPAddress;
44

45
/**
46
 * A request to create a job.
47
 *
48
 * @author Donal Fellows
49
 * @param owner
50
 *            Who owns the job. Ignored when the job is submitted by a
51
 *            non-admin.
52
 * @param group
53
 *            What group will the job be accounted against; the owner
54
 *            <em>must</em> be a member of the group. If {@code null}, the
55
 *            single group that the owner is a member of will be used (with it
56
 *            being an error for that to not exist or not be unique). Only one
57
 *            of group, {@link #nmpiCollab} or {@link #nmpiJobId} must be
58
 *            non-{@code null}, but all can be {@code null}.
59
 * @param nmpiCollab
60
 *            Which NMPI Collab the job will be accounted against; the owner
61
 *            <em>must</em> be a member of the Collab. A session will be created
62
 *            in the Collab and this will be accounted against. Only one of
63
 *            {@link #group}, nmpiCollab or {@link #nmpiJobId} must be
64
 *            non-{@code null}, but all can be {@code null}.
65
 * @param nmpiJobId
66
 *            Which NMPI Job the job will be accounted against; the owner
67
 *            <em>must</em> be able to update the NMPI Job. Only the quota of
68
 *            the NMPI Job will be updated at the end of the job, as will the
69
 *            local quota of the Collab of the NMPI Job. Only one of
70
 *            {@link #group}, {@link #nmpiCollab} or nmpiJobId must be
71
 *            non-{@code null}, but all can be {@code null}.
72
 * @param keepaliveInterval
73
 *            How long after a keepalive message will the job be auto-deleted?
74
 *            <em>Required.</em> Must be between 30 and 300 seconds.
75
 * @param numBoards
76
 *            The number of boards to allocate. May be {@code null} to either
77
 *            use the default (1) or to let one of the other selectors
78
 *            ({@link #dimensions}, {@link #board}) make the choice.
79
 * @param dimensions
80
 *            The dimensions of rectangle of triads of boards to allocate. May
81
 *            be {@code null} to let one of the other selectors
82
 *            ({@link #numBoards}, {@link #board}) make the choice.
83
 * @param board
84
 *            The specific board to allocate. May be {@code null} to let one of
85
 *            the other selectors ({@link #numBoards}, {@link #dimensions}) make
86
 *            the choice.
87
 * @param machineName
88
 *            Which machine to allocate on. This and {@link #tags} are mutually
89
 *            exclusive, but at least one must be given.
90
 * @param tags
91
 *            The tags to select which machine to allocate on. This and
92
 *            {@link #machineName} are mutually exclusive, but at least one must
93
 *            be given.
94
 * @param maxDeadBoards
95
 *            The maximum number of dead boards allowed in a rectangular
96
 *            allocation. Note that the allocation engine might increase this if
97
 *            it decides to overallocate. Defaults to {@code 0}.
98
 */
99
public record CreateJobRequest(@JsonProperty String owner,
1✔
100
                @JsonProperty String group,
101
                @JsonProperty("nmpi-collab") String nmpiCollab,
102
                @Positive(message = "negative NMPI job IDs are unsupported") //
103
                @JsonProperty("nmpi-job-id") Integer nmpiJobId,
104
                @JsonProperty("keepalive-interval")
105
                @NotNull(message = "keepalive-interval is "
106
                                + "required") Duration keepaliveInterval,
107
                @JsonProperty("num-boards") @Positive(message = "number of boards "
108
                                + "must be at least 1 if given") Integer numBoards,
109
                @JsonProperty @Valid Dimensions dimensions,
110
                @JsonProperty @Valid SpecificBoard board,
111
                @JsonProperty("machine-name") String machineName,
112
                @JsonProperty List<@NotBlank(//
113
                                message = "tags must not be blank") String> tags,
114
                @JsonProperty("max-dead-boards") @PositiveOrZero(message = //
115
                                "max-dead-boards may not be negative") Integer maxDeadBoards) {
116
        // Extended validation
117

118
        @Keep
119
        @JsonIgnore
120
        @AssertTrue(message = "either machine-name or tags must be supplied")
121
        private boolean isMachineNameAndTagsMutuallyExclusive() {
122
                return nonNull(machineName) != nonNull(tags);
×
123
        }
124

125
        @Keep
126
        @JsonIgnore
127
        @AssertFalse(message = "machine-name, if given, must be non-blank")
128
        private boolean isMachineNameInsane() {
129
                return nonNull(machineName) && machineName.isBlank();
×
130
        }
131

132
        @Keep
133
        @JsonIgnore
134
        @AssertFalse(message = "group, if given, must be non-blank")
135
        private boolean isGroupInsane() {
136
                return nonNull(group) && group.isBlank();
×
137
        }
138

139
        @Keep
140
        @JsonIgnore
141
        @AssertFalse(message = "nmpi-collab, if given, must be non-blank")
142
        private boolean isCollabInsane() {
143
                return nonNull(nmpiCollab) && nmpiCollab.isBlank();
×
144
        }
145

146
        @Keep
147
        @JsonIgnore
148
        @AssertTrue(
149
                        message = "either specify num-boards or dimensions and/or board")
150
        private boolean isOverLocated() {
151
                int count = 0;
×
152
                if (nonNull(numBoards)) {
×
153
                        count++;
×
154
                }
155
                if (nonNull(dimensions) || nonNull(board)) {
×
156
                        count++;
×
157
                }
158
                return count <= 1;
×
159
        }
160

161
        @Keep
162
        @JsonIgnore
163
        @AssertTrue(message = "only at most one of group, nmpi-collab and "
164
                        + "nmpi-job-id can be given")
165
        private boolean isGroupLocatableInAtMostOneWayOnly() {
166
                int count = 0;
×
167
                if (nonNull(group)) {
×
168
                        count++;
×
169
                }
170
                if (nonNull(nmpiCollab)) {
×
171
                        count++;
×
172
                }
173
                if (nonNull(nmpiJobId)) {
×
174
                        count++;
×
175
                }
176
                return count <= 1;
×
177
        }
178

179
        private static final Duration MIN_KEEPALIVE = Duration.parse("PT30S");
1✔
180

181
        private static final Duration MAX_KEEPALIVE = Duration.parse("PT300S");
1✔
182

183
        @Keep
184
        @JsonIgnore
185
        @AssertTrue(message = "keepalive-interval must be 30 to 300 seconds")
186
        private boolean isKeepaliveIntervalInRange() {
187
                /*
188
                 * Really ought to be validated against config, but we've not got the
189
                 * config at this point.
190
                 */
191
                return keepaliveInterval == null
×
192
                                || (keepaliveInterval.compareTo(MAX_KEEPALIVE) <= 0
×
193
                                        && keepaliveInterval.compareTo(MIN_KEEPALIVE) >= 0);
×
194
        }
195

196
        /**
197
         * Describes a request for an allocation of given dimensions.
198
         *
199
         * @param width
200
         *            The width of the rectangle of boards to allocate, in triads.
201
         * @param height
202
         *            The height of the rectangle of boards to allocate, in triads.
203
         */
204
        public record Dimensions(@ValidTriadWidth int width,
1✔
205
                        @ValidTriadHeight int height) {
206
        }
207

208
        /**
209
         * Describes a request for a specific board.
210
         *
211
         * @param x
212
         *            The X triad coordinate of the board.
213
         * @param y
214
         *            The Y triad coordinate of the board.
215
         * @param z
216
         *            The Z triad coordinate of the board.
217
         * @param cabinet
218
         *            The physical cabinet number of the board.
219
         * @param frame
220
         *            The physical frame number of the board.
221
         * @param board
222
         *            The physical board number of the board.
223
         * @param address
224
         *            The IP address of the board.
225
         */
226
        public record SpecificBoard(@ValidTriadX Integer x, @ValidTriadY Integer y,
1✔
227
                        @ValidTriadZ Integer z, @ValidCabinetNumber Integer cabinet,
228
                        @ValidFrameNumber Integer frame, @ValidBoardNumber Integer board,
229
                        @IPAddress(nullOK = true, message = "address must be "
230
                                        + "an IP address") String address) {
231
                @JsonIgnore
232
                private boolean isTriadValid() {
233
                        return nonNull(x) && nonNull(y) && nonNull(z);
×
234
                }
235

236
                @JsonIgnore
237
                private boolean isPhysicalValid() {
238
                        return nonNull(cabinet) && nonNull(frame) && nonNull(board);
×
239
                }
240

241
                @JsonIgnore
242
                private boolean isIPValid() {
243
                        return nonNull(address);
×
244
                }
245

246
                /**
247
                 * Does this represent a valid way of identifying a board?
248
                 *
249
                 * @return Yes if at least one way of giving coordinates is valid.
250
                 */
251
                @Keep
252
                @JsonIgnore
253
                @AssertTrue(message = "at least one way of identifying a board "
254
                                + "must be given")
255
                private boolean isSpecificBoardValid() {
256
                        return isTriadValid() || isPhysicalValid() || isIPValid();
×
257
                }
258
        }
259
}
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