17
17
18
18
package org .openqa .selenium .grid .distributor ;
19
19
20
- import com .google .common .collect .ImmutableMap ;
21
- import com .google .common .collect .ImmutableSet ;
22
- import org .openqa .selenium .Capabilities ;
23
- import org .openqa .selenium .RetrySessionRequestException ;
24
20
import org .openqa .selenium .SessionNotCreatedException ;
25
- import org .openqa .selenium .grid .data .CreateSessionRequest ;
26
21
import org .openqa .selenium .grid .data .CreateSessionResponse ;
27
22
import org .openqa .selenium .grid .data .DistributorStatus ;
28
23
import org .openqa .selenium .grid .data .NodeId ;
29
24
import org .openqa .selenium .grid .data .NodeStatus ;
30
25
import org .openqa .selenium .grid .data .Session ;
31
- import org .openqa .selenium .grid .data .SlotId ;
26
+ import org .openqa .selenium .grid .data .SessionRequest ;
32
27
import org .openqa .selenium .grid .distributor .selector .SlotSelector ;
33
28
import org .openqa .selenium .grid .node .Node ;
34
29
import org .openqa .selenium .grid .security .RequiresSecretFilter ;
35
30
import org .openqa .selenium .grid .security .Secret ;
36
31
import org .openqa .selenium .grid .sessionmap .SessionMap ;
37
- import org .openqa .selenium .grid .data .SessionRequest ;
38
32
import org .openqa .selenium .internal .Either ;
39
33
import org .openqa .selenium .internal .Require ;
40
34
import org .openqa .selenium .json .Json ;
41
- import org .openqa .selenium .remote .SessionId ;
42
35
import org .openqa .selenium .remote .http .HttpClient ;
43
36
import org .openqa .selenium .remote .http .HttpRequest ;
44
37
import org .openqa .selenium .remote .http .HttpResponse ;
45
38
import org .openqa .selenium .remote .http .Routable ;
46
39
import org .openqa .selenium .remote .http .Route ;
47
- import org .openqa .selenium .remote .tracing .AttributeKey ;
48
- import org .openqa .selenium .remote .tracing .EventAttribute ;
49
- import org .openqa .selenium .remote .tracing .EventAttributeValue ;
50
- import org .openqa .selenium .remote .tracing .Span ;
51
40
import org .openqa .selenium .remote .tracing .SpanDecorator ;
52
- import org .openqa .selenium .remote .tracing .Status ;
53
41
import org .openqa .selenium .remote .tracing .Tracer ;
54
42
import org .openqa .selenium .status .HasReadyState ;
55
43
56
44
import java .io .UncheckedIOException ;
57
- import java .util .HashMap ;
58
- import java .util .Iterator ;
59
45
import java .util .Map ;
60
46
import java .util .Set ;
61
47
import java .util .UUID ;
62
- import java .util .concurrent .locks .Lock ;
63
48
import java .util .concurrent .locks .ReadWriteLock ;
64
49
import java .util .concurrent .locks .ReentrantReadWriteLock ;
65
50
import java .util .function .Predicate ;
66
51
import java .util .logging .Logger ;
67
- import java .util .stream .Collectors ;
68
52
69
- import static org .openqa .selenium .remote .RemoteTags .CAPABILITIES ;
70
- import static org .openqa .selenium .remote .RemoteTags .CAPABILITIES_EVENT ;
71
- import static org .openqa .selenium .remote .RemoteTags .SESSION_ID ;
72
- import static org .openqa .selenium .remote .RemoteTags .SESSION_ID_EVENT ;
73
53
import static org .openqa .selenium .remote .http .Route .delete ;
74
54
import static org .openqa .selenium .remote .http .Route .get ;
75
55
import static org .openqa .selenium .remote .http .Route .post ;
76
- import static org .openqa .selenium .remote .tracing .Tags .EXCEPTION ;
77
56
78
57
/**
79
58
* Responsible for being the central place where the {@link Node}s
@@ -117,20 +96,14 @@ public abstract class Distributor implements HasReadyState, Predicate<HttpReques
117
96
118
97
private final Route routes ;
119
98
protected final Tracer tracer ;
120
- private final SlotSelector slotSelector ;
121
- private final SessionMap sessions ;
122
99
private final ReadWriteLock lock = new ReentrantReadWriteLock (true );
123
100
124
101
protected Distributor (
125
102
Tracer tracer ,
126
103
HttpClient .Factory httpClientFactory ,
127
- SlotSelector slotSelector ,
128
- SessionMap sessions ,
129
104
Secret registrationSecret ) {
130
105
this .tracer = Require .nonNull ("Tracer" , tracer );
131
106
Require .nonNull ("HTTP client factory" , httpClientFactory );
132
- this .slotSelector = Require .nonNull ("Slot selector" , slotSelector );
133
- this .sessions = Require .nonNull ("Session map" , sessions );
134
107
135
108
Require .nonNull ("Registration secret" , registrationSecret );
136
109
@@ -150,132 +123,16 @@ protected Distributor(
150
123
.to (params ->
151
124
new RemoveNode (this , new NodeId (UUID .fromString (params .get ("nodeId" )))))
152
125
.with (requiresSecret ),
153
- get ("/se/grid/distributor/status" )
126
+ post ("/se/grid/distributor/session" )
127
+ .to (() -> new CreateSession (this ))
128
+ .with (requiresSecret ),
129
+ get ("/se/grid/distributor/status" )
154
130
.to (() -> new GetDistributorStatus (this ))
155
131
.with (new SpanDecorator (tracer , req -> "distributor.status" )));
156
132
}
157
133
158
- public Either <SessionNotCreatedException , CreateSessionResponse > newSession (SessionRequest request )
159
- throws SessionNotCreatedException {
160
- Require .nonNull ("Requests to process" , request );
161
-
162
- Span span = tracer .getCurrentContext ().createSpan ("distributor.create_session_response" );
163
- Map <String , EventAttributeValue > attributeMap = new HashMap <>();
164
- try {
165
- attributeMap .put (AttributeKey .LOGGER_CLASS .getKey (),
166
- EventAttribute .setValue (getClass ().getName ()));
167
-
168
- Iterator <Capabilities > iterator = request .getDesiredCapabilities ().iterator ();
169
- attributeMap .put ("request.payload" , EventAttribute .setValue (request .getDesiredCapabilities ().toString ()));
170
- String sessionReceivedMessage = "Session request received by the distributor" ;
171
- span .addEvent (sessionReceivedMessage , attributeMap );
172
- LOG .info (String .format ("%s: \n %s" , sessionReceivedMessage , request .getDesiredCapabilities ()));
173
-
174
- if (!iterator .hasNext ()) {
175
- SessionNotCreatedException exception =
176
- new SessionNotCreatedException ("No capabilities found in session request payload" );
177
- EXCEPTION .accept (attributeMap , exception );
178
- attributeMap .put (AttributeKey .EXCEPTION_MESSAGE .getKey (),
179
- EventAttribute .setValue ("Unable to create session. No capabilities found: " +
180
- exception .getMessage ()));
181
- span .addEvent (AttributeKey .EXCEPTION_EVENT .getKey (), attributeMap );
182
- return Either .left (exception );
183
- }
184
-
185
- Either <SessionNotCreatedException , CreateSessionResponse > selected ;
186
- CreateSessionRequest firstRequest = new CreateSessionRequest (
187
- request .getDownstreamDialects (),
188
- iterator .next (),
189
- ImmutableMap .of ("span" , span ));
190
-
191
- Lock writeLock = this .lock .writeLock ();
192
- writeLock .lock ();
193
- try {
194
- Set <NodeStatus > model = ImmutableSet .copyOf (getAvailableNodes ());
195
-
196
- // Reject new session immediately if no node has the required capabilities
197
- boolean hostsWithCaps = model .stream ()
198
- .anyMatch (nodeStatus -> nodeStatus .hasCapability (firstRequest .getDesiredCapabilities ()));
199
-
200
- if (!hostsWithCaps ) {
201
- String errorMessage = String .format (
202
- "No Node supports the required capabilities: %s" ,
203
- request .getDesiredCapabilities ().stream ().map (Capabilities ::toString )
204
- .collect (Collectors .joining (", " )));
205
- SessionNotCreatedException exception = new SessionNotCreatedException (errorMessage );
206
- span .setAttribute (AttributeKey .ERROR .getKey (), true );
207
- span .setStatus (Status .ABORTED );
208
-
209
- EXCEPTION .accept (attributeMap , exception );
210
- attributeMap .put (AttributeKey .EXCEPTION_MESSAGE .getKey (),
211
- EventAttribute .setValue ("Unable to create session: " + exception .getMessage ()));
212
- span .addEvent (AttributeKey .EXCEPTION_EVENT .getKey (), attributeMap );
213
- return Either .left (exception );
214
- }
215
-
216
- // Find a Node that supports the capabilities present in the new session
217
- Set <SlotId > slotIds = slotSelector .selectSlot (firstRequest .getDesiredCapabilities (), model );
218
- if (!slotIds .isEmpty ()) {
219
- selected = reserve (slotIds .iterator ().next (), firstRequest );
220
- } else {
221
- String errorMessage =
222
- String .format (
223
- "Unable to find provider for session: %s" ,
224
- request .getDesiredCapabilities ().stream ().map (Capabilities ::toString )
225
- .collect (Collectors .joining (", " )));
226
- SessionNotCreatedException exception = new RetrySessionRequestException (errorMessage );
227
- selected = Either .left (exception );
228
- }
229
- } finally {
230
- writeLock .unlock ();
231
- }
232
-
233
- if (selected .isRight ()) {
234
- CreateSessionResponse sessionResponse = selected .right ();
235
-
236
- sessions .add (sessionResponse .getSession ());
237
- SessionId sessionId = sessionResponse .getSession ().getId ();
238
- Capabilities caps = sessionResponse .getSession ().getCapabilities ();
239
- String sessionUri = sessionResponse .getSession ().getUri ().toString ();
240
- SESSION_ID .accept (span , sessionId );
241
- CAPABILITIES .accept (span , caps );
242
- SESSION_ID_EVENT .accept (attributeMap , sessionId );
243
- CAPABILITIES_EVENT .accept (attributeMap , caps );
244
- span .setAttribute (AttributeKey .SESSION_URI .getKey (), sessionUri );
245
- attributeMap .put (AttributeKey .SESSION_URI .getKey (), EventAttribute .setValue (sessionUri ));
246
-
247
- String sessionCreatedMessage = "Session created by the distributor" ;
248
- span .addEvent (sessionCreatedMessage , attributeMap );
249
- LOG .info (String .format ("%s. Id: %s, Caps: %s" , sessionCreatedMessage , sessionId , caps ));
250
- return Either .right (sessionResponse );
251
-
252
- } else {
253
- return selected ;
254
- }
255
- } catch (SessionNotCreatedException e ) {
256
- span .setAttribute (AttributeKey .ERROR .getKey (), true );
257
- span .setStatus (Status .ABORTED );
258
-
259
- EXCEPTION .accept (attributeMap , e );
260
- attributeMap .put (AttributeKey .EXCEPTION_MESSAGE .getKey (),
261
- EventAttribute .setValue ("Unable to create session: " + e .getMessage ()));
262
- span .addEvent (AttributeKey .EXCEPTION_EVENT .getKey (), attributeMap );
263
-
264
- return Either .left (e );
265
- } catch (UncheckedIOException e ) {
266
- span .setAttribute (AttributeKey .ERROR .getKey (), true );
267
- span .setStatus (Status .UNKNOWN );
268
-
269
- EXCEPTION .accept (attributeMap , e );
270
- attributeMap .put (AttributeKey .EXCEPTION_MESSAGE .getKey (),
271
- EventAttribute .setValue ("Unknown error in LocalDistributor while creating session: " + e .getMessage ()));
272
- span .addEvent (AttributeKey .EXCEPTION_EVENT .getKey (), attributeMap );
273
-
274
- return Either .left (new SessionNotCreatedException (e .getMessage (), e ));
275
- } finally {
276
- span .close ();
277
- }
278
- }
134
+ public abstract Either <SessionNotCreatedException , CreateSessionResponse > newSession (SessionRequest request )
135
+ throws SessionNotCreatedException ;
279
136
280
137
public abstract Distributor add (Node node );
281
138
@@ -285,12 +142,6 @@ public Either<SessionNotCreatedException, CreateSessionResponse> newSession(Sess
285
142
286
143
public abstract DistributorStatus getStatus ();
287
144
288
- protected abstract Set <NodeStatus > getAvailableNodes ();
289
-
290
- protected abstract Either <SessionNotCreatedException , CreateSessionResponse > reserve (
291
- SlotId slot ,
292
- CreateSessionRequest request );
293
-
294
145
@ Override
295
146
public boolean test (HttpRequest httpRequest ) {
296
147
return matches (httpRequest );
0 commit comments