Skip to content

Commit 830b966

Browse files
committed
[grid] Add Node session-history endpoint and write to local file for other utility to consume
1 parent 6a58efb commit 830b966

File tree

15 files changed

+758
-4
lines changed

15 files changed

+758
-4
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.grid.data;
19+
20+
import java.time.Instant;
21+
import java.util.Objects;
22+
import org.openqa.selenium.internal.Require;
23+
import org.openqa.selenium.remote.SessionId;
24+
25+
public class SessionHistoryEntry {
26+
private final SessionId sessionId;
27+
private final Instant startTime;
28+
private Instant stopTime;
29+
30+
public SessionHistoryEntry(SessionId sessionId, Instant startTime, Instant stopTime) {
31+
this.sessionId = Require.nonNull("Session ID", sessionId);
32+
this.startTime = Require.nonNull("Start time", startTime);
33+
this.stopTime = stopTime; // Can be null for ongoing sessions
34+
}
35+
36+
public SessionId getSessionId() {
37+
return sessionId;
38+
}
39+
40+
public Instant getStartTime() {
41+
return startTime;
42+
}
43+
44+
public Instant getStopTime() {
45+
return stopTime;
46+
}
47+
48+
public void setStopTime(Instant stopTime) {
49+
this.stopTime = stopTime;
50+
}
51+
52+
@Override
53+
public boolean equals(Object o) {
54+
if (this == o) return true;
55+
if (!(o instanceof SessionHistoryEntry)) return false;
56+
SessionHistoryEntry that = (SessionHistoryEntry) o;
57+
return Objects.equals(sessionId, that.sessionId)
58+
&& Objects.equals(startTime, that.startTime)
59+
&& Objects.equals(stopTime, that.stopTime);
60+
}
61+
62+
@Override
63+
public int hashCode() {
64+
return Objects.hash(sessionId, startTime, stopTime);
65+
}
66+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.grid.data;
19+
20+
import java.util.function.Consumer;
21+
import org.openqa.selenium.events.Event;
22+
import org.openqa.selenium.events.EventListener;
23+
import org.openqa.selenium.events.EventName;
24+
import org.openqa.selenium.internal.Require;
25+
import org.openqa.selenium.remote.SessionId;
26+
27+
public class SessionStartedEvent extends Event {
28+
29+
private static final EventName SESSION_STARTED = new EventName("session-started");
30+
31+
public SessionStartedEvent(SessionId id) {
32+
super(SESSION_STARTED, id);
33+
}
34+
35+
public static EventListener<SessionId> listener(Consumer<SessionId> handler) {
36+
Require.nonNull("Handler", handler);
37+
38+
return new EventListener<>(SESSION_STARTED, SessionId.class, handler);
39+
}
40+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.grid.data;
19+
20+
public enum SessionStatus {
21+
SUCCESS,
22+
FAILED
23+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.grid.node;
19+
20+
import static org.openqa.selenium.remote.http.Contents.asJson;
21+
22+
import com.google.common.collect.ImmutableMap;
23+
import java.io.UncheckedIOException;
24+
import java.util.List;
25+
import org.openqa.selenium.grid.data.SessionHistoryEntry;
26+
import org.openqa.selenium.internal.Require;
27+
import org.openqa.selenium.remote.http.HttpHandler;
28+
import org.openqa.selenium.remote.http.HttpRequest;
29+
import org.openqa.selenium.remote.http.HttpResponse;
30+
31+
class GetNodeSessionHistory implements HttpHandler {
32+
33+
private final Node node;
34+
35+
GetNodeSessionHistory(Node node) {
36+
this.node = Require.nonNull("Node", node);
37+
}
38+
39+
@Override
40+
public HttpResponse execute(HttpRequest req) throws UncheckedIOException {
41+
List<SessionHistoryEntry> sessionHistory = node.getSessionHistory();
42+
43+
return new HttpResponse().setContent(asJson(ImmutableMap.of("value", sessionHistory)));
44+
}
45+
}

java/src/org/openqa/selenium/grid/node/Node.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.io.IOException;
3030
import java.net.URI;
3131
import java.time.Duration;
32+
import java.util.List;
3233
import java.util.Map;
3334
import java.util.ServiceLoader;
3435
import java.util.Set;
@@ -45,6 +46,7 @@
4546
import org.openqa.selenium.grid.data.NodeId;
4647
import org.openqa.selenium.grid.data.NodeStatus;
4748
import org.openqa.selenium.grid.data.Session;
49+
import org.openqa.selenium.grid.data.SessionHistoryEntry;
4850
import org.openqa.selenium.grid.security.RequiresSecretFilter;
4951
import org.openqa.selenium.grid.security.Secret;
5052
import org.openqa.selenium.internal.Either;
@@ -189,6 +191,9 @@ protected Node(
189191
delete("/se/grid/node/session/{sessionId}")
190192
.to(params -> new StopNodeSession(this, sessionIdFrom(params)))
191193
.with(spanDecorator("node.stop_session").andThen(requiresSecret)),
194+
get("/se/grid/node/session-history")
195+
.to(() -> new GetNodeSessionHistory(this))
196+
.with(spanDecorator("node.get_session_history").andThen(requiresSecret)),
192197
get("/se/grid/node/session/{sessionId}")
193198
.to(params -> new GetNodeSession(this, sessionIdFrom(params)))
194199
.with(spanDecorator("node.get_session").andThen(requiresSecret)),
@@ -266,6 +271,8 @@ public TemporaryFilesystem getDownloadsFilesystem(SessionId id) throws IOExcepti
266271

267272
public abstract NodeStatus getStatus();
268273

274+
public abstract List<SessionHistoryEntry> getSessionHistory();
275+
269276
public abstract HealthCheck getHealthCheck();
270277

271278
public Duration getSessionTimeout() {

java/src/org/openqa/selenium/grid/node/config/NodeFlags.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,27 @@ public class NodeFlags implements HasRoles {
283283
@ConfigValue(section = NODE_SECTION, name = "enable-managed-downloads", example = "false")
284284
public Boolean managedDownloadsEnabled;
285285

286+
@Parameter(
287+
names = {"--status-to-file"},
288+
description =
289+
"Path to a local file where the Node will write its status information "
290+
+ "in JSON format. This file will be updated periodically and can be "
291+
+ "consumed by other services running on the same machine.")
292+
@ConfigValue(section = NODE_SECTION, name = "status-to-file", example = "node-status.json")
293+
public String statusFile;
294+
295+
@Parameter(
296+
names = {"--session-history-to-file"},
297+
description =
298+
"Path to a local file where the Node will write session history information "
299+
+ "in JSON format. This file will contain chronological records of session "
300+
+ "start and stop events with sessionId, startTime, and stopTime.")
301+
@ConfigValue(
302+
section = NODE_SECTION,
303+
name = "session-history-to-file",
304+
example = "session-history.json")
305+
public String sessionHistoryFile;
306+
286307
@Override
287308
public Set<Role> getRoles() {
288309
return Collections.singleton(NODE_ROLE);

java/src/org/openqa/selenium/grid/node/config/NodeOptions.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,14 @@ public boolean isManagedDownloadsEnabled() {
168168
return config.getBool(NODE_SECTION, "enable-managed-downloads").orElse(Boolean.FALSE);
169169
}
170170

171+
public Optional<String> getStatusFile() {
172+
return config.get(NODE_SECTION, "status-to-file");
173+
}
174+
175+
public Optional<String> getSessionHistoryFile() {
176+
return config.get(NODE_SECTION, "session-history-to-file");
177+
}
178+
171179
public String getGridSubPath() {
172180
return normalizeSubPath(getPublicGridUri().map(URI::getPath).orElse(""));
173181
}

0 commit comments

Comments
 (0)