Skip to content

Commit eb4b587

Browse files
committed
K8s: Bump new KEDA image for feature preview
Signed-off-by: Viet Nguyen Duc <[email protected]>
1 parent 6f262a3 commit eb4b587

File tree

6 files changed

+191
-52
lines changed

6 files changed

+191
-52
lines changed

.keda/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ You can involve to review and discuss the pull requests to help us early detect
4949

5050
[kedacore/keda](https://github.com/kedacore/keda)
5151

52+
- https://github.com/kedacore/keda/pull/6570 (plan, v2.17.0)
53+
5254
- https://github.com/kedacore/keda/pull/6536 (plan, v2.17.0)
5355

5456
- https://github.com/kedacore/keda/pull/6477 (plan, v2.17.0)
@@ -61,6 +63,8 @@ You can involve to review and discuss the pull requests to help us early detect
6163

6264
[kedacore/keda-docs](https://github.com/kedacore/keda-docs)
6365

66+
- https://github.com/kedacore/keda-docs/pull/1542 (plan, v2.17.0)
67+
6468
- https://github.com/kedacore/keda-docs/pull/1533 (plan, v2.17.0)
6569

6670
- https://github.com/kedacore/keda-docs/pull/1522 (plan, v2.17.0)

.keda/scalers/selenium-grid-scaler.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ triggers:
3939
- `activationThreshold` - Target value for activating the scaler. Learn more about activation [here](./../concepts/scaling-deployments.md#activating-and-scaling-thresholds). (Default: `0`, Optional)
4040
- `platformName` - Name of the browser platform. Refer to the [Selenium Grid's](https://www.selenium.dev/documentation/en/getting_started_with_webdriver/browsers/) and [WebdriverIO's](https://webdriver.io/docs/options/#capabilities) documentation for more info. (Optional)
4141
- `nodeMaxSessions` - Number of maximum sessions that can run in parallel on a Node. Update this parameter align with node config `--max-sessions` (`SE_NODE_MAX_SESSIONS`) to have the correct scaling behavior. (Default: `1`, Optional).
42+
- `enableManagedDownloads`- Set this for Node enabled to auto manage files downloaded for a given session on the Node. When the client requests enabling this feature, it can only be assigned to the Node that also enabled it. Otherwise, the request will wait until it timed out. (Default: `false`, Optional).
4243
- `capabilities` - Add more custom capabilities for matching specific Nodes. It should be in JSON string, see [example](https://www.selenium.dev/documentation/grid/configuration/toml_options/#setting-custom-capabilities-for-matching-specific-nodes) (Optional)
4344

4445
**Trigger Authentication**
@@ -224,6 +225,70 @@ options.set_capability('browserVersion', '131.0')
224225
driver = webdriver.Remote(options=options, command_executor=SELENIUM_GRID_URL)
225226
```
226227

228+
#### Selenium Grid scaler trigger metadata with Node `enableManagedDownloads`
229+
230+
In image `selenium/node-chrome`, the environment variable `SE_NODE_ENABLE_MANAGED_DOWNLOADS` is used to append the `--enable-managed-downloads` CLI option to the Node. This option is used to enable the Node to auto manage files downloaded for a given session on the Node. The request with enabling this feature can only be assigned to the Node also enabled it, otherwise the request will be waited until request timed out.
231+
232+
```yaml
233+
kind: Deployment
234+
metadata:
235+
name: selenium-node-chrome
236+
labels:
237+
deploymentName: selenium-node-chrome
238+
spec:
239+
replicas: 1
240+
template:
241+
spec:
242+
containers:
243+
- name: selenium-node-chrome
244+
image: selenium/node-chrome:132.0
245+
ports:
246+
- containerPort: 5555
247+
env:
248+
- name: SE_NODE_BROWSER_VERSION
249+
value: '132.0'
250+
- name: SE_NODE_PLATFORM_NAME
251+
value: 'Linux'
252+
# https://www.selenium.dev/documentation/grid/configuration/cli_options/#node
253+
- name: SE_NODE_ENABLE_MANAGED_DOWNLOADS
254+
value: "true"
255+
256+
---
257+
258+
apiVersion: keda.sh/v1alpha1
259+
kind: ScaledObject
260+
metadata:
261+
name: selenium-grid-scaledobject-chrome-132
262+
namespace: keda
263+
labels:
264+
deploymentName: selenium-node-chrome-132
265+
spec:
266+
maxReplicaCount: 8
267+
scaleTargetRef:
268+
name: selenium-node-chrome-132
269+
triggers:
270+
- type: selenium-grid
271+
metadata:
272+
url: 'http://selenium-hub:4444/graphql'
273+
browserName: 'chrome'
274+
platformName: 'Linux'
275+
browserVersion: '132.0'
276+
unsafeSsl: 'true'
277+
# Scaler trigger param configuration should be aligned with Node stereotype.
278+
enableManagedDownloads: "true"
279+
```
280+
281+
The request to trigger this scaler should be
282+
283+
```python
284+
options = ChromeOptions()
285+
options.set_capability('platformName', 'Linux')
286+
options.set_capability('browserVersion', '132.0')
287+
# https://www.selenium.dev/documentation/webdriver/drivers/remote_webdriver/#enable-downloads-in-the-grid
288+
options.enable_downloads = True
289+
driver = webdriver.Remote(options=options, command_executor=SELENIUM_GRID_URL)
290+
```
291+
227292
---
228293
#### Selenium Grid scaler trigger metadata with extra `capabilities`
229294

.keda/scalers/selenium_grid_scaler.go

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,20 @@ type seleniumGridScaler struct {
2828
type seleniumGridScalerMetadata struct {
2929
triggerIndex int
3030

31-
URL string `keda:"name=url, order=authParams;triggerMetadata"`
32-
AuthType string `keda:"name=authType, order=authParams;resolvedEnv, optional"`
33-
Username string `keda:"name=username, order=authParams;resolvedEnv, optional"`
34-
Password string `keda:"name=password, order=authParams;resolvedEnv, optional"`
35-
AccessToken string `keda:"name=accessToken, order=authParams;resolvedEnv, optional"`
36-
BrowserName string `keda:"name=browserName, order=triggerMetadata, optional"`
37-
SessionBrowserName string `keda:"name=sessionBrowserName, order=triggerMetadata, optional"`
38-
BrowserVersion string `keda:"name=browserVersion, order=triggerMetadata, optional"`
39-
PlatformName string `keda:"name=platformName, order=triggerMetadata, optional"`
40-
ActivationThreshold int64 `keda:"name=activationThreshold, order=triggerMetadata, optional"`
41-
UnsafeSsl bool `keda:"name=unsafeSsl, order=triggerMetadata, default=false"`
42-
NodeMaxSessions int64 `keda:"name=nodeMaxSessions, order=triggerMetadata, default=1"`
43-
Capabilities string `keda:"name=capabilities, order=triggerMetadata, optional"`
31+
URL string `keda:"name=url, order=authParams;triggerMetadata"`
32+
AuthType string `keda:"name=authType, order=authParams;resolvedEnv, optional"`
33+
Username string `keda:"name=username, order=authParams;resolvedEnv, optional"`
34+
Password string `keda:"name=password, order=authParams;resolvedEnv, optional"`
35+
AccessToken string `keda:"name=accessToken, order=authParams;resolvedEnv, optional"`
36+
BrowserName string `keda:"name=browserName, order=triggerMetadata, optional"`
37+
SessionBrowserName string `keda:"name=sessionBrowserName, order=triggerMetadata, optional"`
38+
BrowserVersion string `keda:"name=browserVersion, order=triggerMetadata, optional"`
39+
PlatformName string `keda:"name=platformName, order=triggerMetadata, optional"`
40+
ActivationThreshold int64 `keda:"name=activationThreshold, order=triggerMetadata, optional"`
41+
UnsafeSsl bool `keda:"name=unsafeSsl, order=triggerMetadata, default=false"`
42+
NodeMaxSessions int64 `keda:"name=nodeMaxSessions, order=triggerMetadata, default=1"`
43+
EnableManagedDownloads bool `keda:"name=enableManagedDownloads, order=triggerMetadata, optional"`
44+
Capabilities string `keda:"name=capabilities, order=triggerMetadata, optional"`
4445

4546
TargetValue int64
4647
}
@@ -101,8 +102,10 @@ type Stereotypes []struct {
101102
Stereotype map[string]interface{} `json:"stereotype"`
102103
}
103104

105+
const EnableManagedDownloadsCapability = "se:downloadsEnabled"
106+
104107
var ExtensionCapabilitiesPrefixes = []string{"goog:", "moz:", "ms:", "se:"}
105-
var FunctionCapabilitiesPrefixes = []string{"se:downloadsEnabled"}
108+
var FunctionCapabilitiesPrefixes = []string{EnableManagedDownloadsCapability}
106109

107110
// Follow pattern in https://github.com/SeleniumHQ/selenium/blob/trunk/java/src/org/openqa/selenium/grid/data/DefaultSlotMatcher.java
108111
func filterCapabilities(capabilities map[string]interface{}) map[string]interface{} {
@@ -154,6 +157,16 @@ func NewSeleniumGridScaler(config *scalersconfig.ScalerConfig) (Scaler, error) {
154157
}, nil
155158
}
156159

160+
func parseCapabilitiesToMap(_capabilities string) (map[string]interface{}, error) {
161+
capabilities := map[string]interface{}{}
162+
if _capabilities != "" {
163+
if err := json.Unmarshal([]byte(_capabilities), &capabilities); err != nil {
164+
return nil, err
165+
}
166+
}
167+
return capabilities, nil
168+
}
169+
157170
func parseSeleniumGridScalerMetadata(config *scalersconfig.ScalerConfig) (*seleniumGridScalerMetadata, error) {
158171
meta := &seleniumGridScalerMetadata{
159172
TargetValue: 1,
@@ -242,7 +255,7 @@ func (s *seleniumGridScaler) getSessionsQueueLength(ctx context.Context, logger
242255
logger.Error(err, fmt.Sprintf("Error when reading Selenium Grid response body: %s", err))
243256
return -1, -1, err
244257
}
245-
newRequestNodes, onGoingSession, err := getCountFromSeleniumResponse(b, s.metadata.BrowserName, s.metadata.BrowserVersion, s.metadata.SessionBrowserName, s.metadata.PlatformName, s.metadata.NodeMaxSessions, s.metadata.Capabilities, logger)
258+
newRequestNodes, onGoingSession, err := getCountFromSeleniumResponse(b, s.metadata.BrowserName, s.metadata.BrowserVersion, s.metadata.SessionBrowserName, s.metadata.PlatformName, s.metadata.NodeMaxSessions, s.metadata.EnableManagedDownloads, s.metadata.Capabilities, logger)
246259
if err != nil {
247260
logger.Error(err, fmt.Sprintf("Error when getting count from Selenium Grid response: %s", err))
248261
return -1, -1, err
@@ -370,7 +383,7 @@ func updateOrAddReservedNode(reservedNodes []ReservedNodes, nodeID string, slotC
370383
return append(reservedNodes, ReservedNodes{ID: nodeID, SlotCount: slotCount, MaxSession: maxSession})
371384
}
372385

373-
func getCountFromSeleniumResponse(b []byte, browserName string, browserVersion string, sessionBrowserName string, platformName string, nodeMaxSessions int64, _capabilities string, logger logr.Logger) (int64, int64, error) {
386+
func getCountFromSeleniumResponse(b []byte, browserName string, browserVersion string, sessionBrowserName string, platformName string, nodeMaxSessions int64, enableManagedDownloads bool, _capabilities string, logger logr.Logger) (int64, int64, error) {
374387
// Track number of available slots of existing Nodes in the Grid can be reserved for the matched requests
375388
var availableSlots int64
376389
// Track number of matched requests in the sessions queue will be served by this scaler
@@ -380,12 +393,12 @@ func getCountFromSeleniumResponse(b []byte, browserName string, browserVersion s
380393
if err := json.Unmarshal(b, &seleniumResponse); err != nil {
381394
return 0, 0, err
382395
}
383-
capabilities := map[string]interface{}{}
384-
if _capabilities != "" {
385-
if err := json.Unmarshal([]byte(_capabilities), &capabilities); err != nil {
386-
logger.Error(err, fmt.Sprintf("Error when unmarshaling trigger metadata 'capabilities': %s", err))
387-
return 0, 0, err
388-
}
396+
397+
capabilities, err := parseCapabilitiesToMap(_capabilities)
398+
if err != nil {
399+
logger.Error(err, fmt.Sprintf("Error when unmarshaling trigger metadata 'capabilities': %s", err))
400+
} else if enableManagedDownloads {
401+
capabilities[EnableManagedDownloadsCapability] = true
389402
}
390403

391404
var sessionQueueRequests = seleniumResponse.Data.SessionsInfo.SessionQueueRequests

.keda/scalers/selenium_grid_scaler_test.go

Lines changed: 85 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ import (
1111

1212
func Test_getCountFromSeleniumResponse(t *testing.T) {
1313
type args struct {
14-
b []byte
15-
browserName string
16-
sessionBrowserName string
17-
browserVersion string
18-
platformName string
19-
nodeMaxSessions int64
20-
capabilities string
14+
b []byte
15+
browserName string
16+
sessionBrowserName string
17+
browserVersion string
18+
platformName string
19+
nodeMaxSessions int64
20+
enableManagedDownloads bool
21+
capabilities string
2122
}
2223
tests := []struct {
2324
name string
@@ -1949,12 +1950,12 @@ func Test_getCountFromSeleniumResponse(t *testing.T) {
19491950
}
19501951
}
19511952
}`),
1952-
browserName: "chrome",
1953-
sessionBrowserName: "chrome",
1954-
browserVersion: "",
1955-
platformName: "linux",
1956-
nodeMaxSessions: 2,
1957-
capabilities: "{\"se:downloadsEnabled\": true}",
1953+
browserName: "chrome",
1954+
sessionBrowserName: "chrome",
1955+
browserVersion: "",
1956+
platformName: "linux",
1957+
nodeMaxSessions: 2,
1958+
enableManagedDownloads: true,
19581959
},
19591960
wantNewRequestNodes: 1,
19601961
wantOnGoingSessions: 1,
@@ -2013,6 +2014,60 @@ func Test_getCountFromSeleniumResponse(t *testing.T) {
20132014
wantOnGoingSessions: 1,
20142015
wantErr: false,
20152016
},
2017+
{
2018+
name: "4_sessions_requests_with_matching_browserName_and_platformName_when_set_extra_capabilities_and_mangaged_downloads_and_1_request_match_should_return_count_as_1_and_ongoing_1",
2019+
args: args{
2020+
b: []byte(`{
2021+
"data": {
2022+
"grid": {
2023+
"sessionCount": 1,
2024+
"maxSession": 1,
2025+
"totalSlots": 1
2026+
},
2027+
"nodesInfo": {
2028+
"nodes": [
2029+
{
2030+
"id": "node-1",
2031+
"status": "UP",
2032+
"sessionCount": 1,
2033+
"maxSession": 1,
2034+
"slotCount": 1,
2035+
"stereotypes": "[{\"slots\": 1, \"stereotype\": {\"browserName\": \"chrome\", \"browserVersion\": \"\", \"platformName\": \"linux\", \"myApp:version\": \"beta\", \"myApp:scope\": \"internal\", \"se:downloadsEnabled\": true}}]",
2036+
"sessions": [
2037+
{
2038+
"id": "session-1",
2039+
"capabilities": "{\"browserName\": \"chrome\", \"browserVersion\": \"\", \"platformName\": \"linux\", \"myApp:version\": \"beta\", \"myApp:scope\": \"internal\", \"se:downloadsEnabled\": true}",
2040+
"slot": {
2041+
"id": "9ce1edba-72fb-465e-b311-ee473d8d7b64",
2042+
"stereotype": "{\"browserName\": \"chrome\", \"browserVersion\": \"\", \"platformName\": \"linux\", \"myApp:version\": \"beta\", \"myApp:scope\": \"internal\", \"se:downloadsEnabled\": true}"
2043+
}
2044+
}
2045+
]
2046+
}
2047+
]
2048+
},
2049+
"sessionsInfo": {
2050+
"sessionQueueRequests": [
2051+
"{\n \"browserName\": \"chrome\",\n \"platformName\": \"linux\"\n}",
2052+
"{\n \"browserName\": \"chrome\",\n \"myApp:version\": \"beta\",\n \"platformName\": \"linux\"\n}",
2053+
"{\n \"browserName\": \"chrome\",\n \"myApp:version\": \"beta\",\n \"myApp:scope\": \"internal\",\n \"platformName\": \"linux\"\n}",
2054+
"{\n \"browserName\": \"chrome\",\n \"se:downloadsEnabled\": true,\n \"myApp:version\": \"beta\",\n \"myApp:scope\": \"internal\",\n \"platformName\": \"linux\"\n}",
2055+
"{\n \"browserName\": \"chrome\",\n \"platformName\": \"Windows 11\"\n}"]
2056+
}
2057+
}
2058+
}`),
2059+
browserName: "chrome",
2060+
sessionBrowserName: "chrome",
2061+
browserVersion: "",
2062+
platformName: "linux",
2063+
nodeMaxSessions: 1,
2064+
enableManagedDownloads: true,
2065+
capabilities: "{\"myApp:version\": \"beta\", \"myApp:scope\": \"internal\"}",
2066+
},
2067+
wantNewRequestNodes: 1,
2068+
wantOnGoingSessions: 1,
2069+
wantErr: false,
2070+
},
20162071
{
20172072
name: "Given_2_requests_include_1_without_browserVersion_When_scaler_metadata_explicit_name_version_platform_Then_scaler_should_scale_up_for_1_request_has_browserVersion_and_return_0_ongoing_sessions",
20182073
args: args{
@@ -2972,7 +3027,7 @@ func Test_getCountFromSeleniumResponse(t *testing.T) {
29723027
}
29733028
for _, tt := range tests {
29743029
t.Run(tt.name, func(t *testing.T) {
2975-
newRequestNodes, onGoingSessions, err := getCountFromSeleniumResponse(tt.args.b, tt.args.browserName, tt.args.browserVersion, tt.args.sessionBrowserName, tt.args.platformName, tt.args.nodeMaxSessions, tt.args.capabilities, logr.Discard())
3030+
newRequestNodes, onGoingSessions, err := getCountFromSeleniumResponse(tt.args.b, tt.args.browserName, tt.args.browserVersion, tt.args.sessionBrowserName, tt.args.platformName, tt.args.nodeMaxSessions, tt.args.enableManagedDownloads, tt.args.capabilities, logr.Discard())
29763031
if (err != nil) != tt.wantErr {
29773032
t.Errorf("getCountFromSeleniumResponse() error = %v, wantErr %v", err, tt.wantErr)
29783033
return
@@ -3148,25 +3203,27 @@ func Test_parseSeleniumGridScalerMetadata(t *testing.T) {
31483203
"password": "password",
31493204
},
31503205
TriggerMetadata: map[string]string{
3151-
"url": "http://selenium-hub:4444/graphql",
3152-
"browserName": "MicrosoftEdge",
3153-
"sessionBrowserName": "msedge",
3154-
"capabilities": "{\"se:downloadsEnabled\": true}",
3206+
"url": "http://selenium-hub:4444/graphql",
3207+
"browserName": "MicrosoftEdge",
3208+
"sessionBrowserName": "msedge",
3209+
"enableManagedDownloads": "true",
3210+
"capabilities": "{\"myApp:version\": \"beta\"}",
31553211
},
31563212
},
31573213
},
31583214
wantErr: false,
31593215
want: &seleniumGridScalerMetadata{
3160-
URL: "http://selenium-hub:4444/graphql",
3161-
BrowserName: "MicrosoftEdge",
3162-
SessionBrowserName: "msedge",
3163-
TargetValue: 1,
3164-
BrowserVersion: "",
3165-
PlatformName: "",
3166-
Username: "username",
3167-
Password: "password",
3168-
NodeMaxSessions: 1,
3169-
Capabilities: "{\"se:downloadsEnabled\": true}",
3216+
URL: "http://selenium-hub:4444/graphql",
3217+
BrowserName: "MicrosoftEdge",
3218+
SessionBrowserName: "msedge",
3219+
TargetValue: 1,
3220+
BrowserVersion: "",
3221+
PlatformName: "",
3222+
Username: "username",
3223+
Password: "password",
3224+
NodeMaxSessions: 1,
3225+
EnableManagedDownloads: true,
3226+
Capabilities: "{\"myApp:version\": \"beta\"}",
31703227
},
31713228
},
31723229
{

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ KEDA_TAG_PREV_VERSION := $(or $(KEDA_TAG_PREV_VERSION),$(KEDA_TAG_PREV_VERSION),
3434
KEDA_CORE_VERSION := $(or $(KEDA_CORE_VERSION),$(KEDA_CORE_VERSION),2.16.1)
3535
KEDA_TAG_VERSION := $(or $(KEDA_TAG_VERSION),$(KEDA_TAG_VERSION),2.16.1-selenium-grid)
3636
KEDA_BASED_NAME := $(or $(KEDA_BASED_NAME),$(KEDA_BASED_NAME),ndviet)
37-
KEDA_BASED_TAG := $(or $(KEDA_BASED_TAG),$(KEDA_BASED_TAG),2.16.1-selenium-grid-20250210)
37+
KEDA_BASED_TAG := $(or $(KEDA_BASED_TAG),$(KEDA_BASED_TAG),2.16.1-selenium-grid-20250225)
3838
TEST_PATCHED_KEDA := $(or $(TEST_PATCHED_KEDA),$(TEST_PATCHED_KEDA),true)
3939

4040
all: hub \

charts/selenium-grid/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ dependencies:
2121
- repository: https://prometheus-community.github.io/helm-charts
2222
version: 69.4.1
2323
name: kube-prometheus-stack
24-
condition: monitoring.enabled, prometheus-stack.enabled
24+
condition: monitoring.enabled, kube-prometheus-stack.enabled
2525
- repository: https://charts.bitnami.com/bitnami
2626
version: 16.4.1
2727
name: postgresql

0 commit comments

Comments
 (0)