Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions qa-integration/pmm_psmdb-pbm_setup/start-sharded-with-pmm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,74 @@ docker compose -f docker-compose-sharded-with-pmm.yaml exec -T rscfg01 mongo --q
EOF
sleep 60
echo
echo "configuring root user on primary rscfg01 configserver replicaset"
docker compose -f docker-compose-sharded-with-pmm.yaml exec -T rscfg01 mongo --quiet << EOF
db.getSiblingDB("admin").createUser({ user: "root", pwd: "root", roles: [ "root", "userAdminAnyDatabase", "clusterAdmin" ] });
EOF
echo
echo "configuring pbm and pmm roles on configserver replicaset rscfg"
docker compose -f docker-compose-sharded-with-pmm.yaml exec -T rscfg01 mongo "mongodb://root:root@localhost/?replicaSet=rscfg" --quiet << EOF
db.getSiblingDB("admin").createRole({
"role": "pbmAnyAction",
"privileges": [{
"resource": { "anyResource": true },
"actions": [ "anyAction" ]
}],
"roles": []
});
db.getSiblingDB("admin").createRole({
role: "explainRole",
privileges: [{
resource: {
db: "",
collection: ""
},
actions: [
"listIndexes",
"listCollections",
"dbStats",
"dbHash",
"collStats",
"find"
]
}],
roles:[]
});
EOF
echo
echo "creating pbm user for configserver replicaset rscfg"
docker compose -f docker-compose-sharded-with-pmm.yaml exec -T rscfg01 mongo "mongodb://root:root@localhost/?replicaSet=rscfg" --quiet << EOF
db.getSiblingDB("admin").createUser({
user: "${pbm_user}",
pwd: "${pbm_pass}",
"roles" : [
{ "db" : "admin", "role" : "readWrite", "collection": "" },
{ "db" : "admin", "role" : "backup" },
{ "db" : "admin", "role" : "clusterMonitor" },
{ "db" : "admin", "role" : "restore" },
{ "db" : "admin", "role" : "pbmAnyAction" }
]
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.
EOF
echo
echo "creating pmm user for configserver replicaset rscfg"
docker compose -f docker-compose-sharded-with-pmm.yaml exec -T rscfg01 mongo "mongodb://root:root@localhost/?replicaSet=rscfg" --quiet << EOF
db.getSiblingDB("admin").createUser({
user: "${pmm_user}",
pwd: "${pmm_pass}",
roles: [
{ role: "explainRole", db: "admin" },
{ role: "clusterMonitor", db: "admin" },
{ role: "read", db: "local" },
{ "db" : "admin", "role" : "readWrite", "collection": "" },
{ "db" : "admin", "role" : "backup" },
{ "db" : "admin", "role" : "clusterMonitor" },
{ "db" : "admin", "role" : "restore" },
{ "db" : "admin", "role" : "pbmAnyAction" }
]
});
EOF
echo
echo "adding shards and creating global mongo user"
docker compose -f docker-compose-sharded-with-pmm.yaml exec -T mongos mongo --quiet << EOF
db.getSiblingDB("admin").createUser({ user: "root", pwd: "root", roles: [ "root", "userAdminAnyDatabase", "clusterAdmin" ] });
Expand Down Expand Up @@ -241,6 +309,34 @@ docker compose -f docker-compose-sharded-with-pmm.yaml exec -T rscfg01 pmm-admin

echo "adding some data"
docker compose -f docker-compose-sharded-with-pmm.yaml exec -T mongos mgodatagen -f /etc/datagen/sharded.json --uri=mongodb://root:root@127.0.0.1:27017

echo "writing chunk-activity generator so the chunk-move/split dashboards keep getting data"
docker compose -f docker-compose-sharded-with-pmm.yaml exec -T mongos tee /tmp/keep_chunks_moving.js > /dev/null << 'JSEOF'
var shards = db.getSiblingDB("config").shards.find().toArray().map(function (s) { return s._id; });
var ins = db.getSiblingDB("test").test.insertOne({ ts: new Date() });
shards.forEach(function (target) {
try {
sh.moveChunk("test.test", { _id: ins.insertedId }, target);
} catch (e) {
print("moveChunk to " + target + " failed, skipping: " + e);
}
});
try {
sh.splitFind("test.test", { _id: ins.insertedId });
Comment on lines +316 to +325

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

found=0
while IFS= read -r config; do
  found=1
  echo "== $config =="
  rg -n -C 6 'test|collection|namespace|shard|key|_id' "$config"
done < <(fd -i -t f 'sharded\.json$')

if [ "$found" -eq 0 ]; then
  echo "No sharded.json file found" >&2
  exit 1
fi

Repository: percona/pmm-qa

Length of output: 204


🏁 Script executed:

set -euo pipefail
printf '%s\n' '== candidate files =='
fd -i -t f 'sharded\.json$|start-sharded-with-pmm\.sh$|datagen' . || true
printf '%s\n' '== relevant references =='
rg -n -C 8 'sharded\.json|test\.test|moveChunk|splitFind|shardCollection|shardKey|_id' qa-integration .github 2>/dev/null || true

Repository: percona/pmm-qa

Length of output: 50371


🏁 Script executed:

set -euo pipefail
printf '%s\n' '== sharded.json =='
cat -n qa-integration/pmm_psmdb-pbm_setup/conf/datagen/sharded.json
printf '%s\n' '== generator and surrounding setup =='
sed -n '295,345p' qa-integration/pmm_psmdb-pbm_setup/start-sharded-with-pmm.sh
printf '%s\n' '== compose image and datagen mounts =='
rg -n -C 5 'mongos:|mongo:|mgodatagen|datagen|image:' qa-integration/pmm_psmdb-pbm_setup/docker-compose-sharded-with-pmm.yaml

Repository: percona/pmm-qa

Length of output: 7934


🏁 Script executed:

set -euo pipefail
printf '%s\n' '== image definition =='
cat -n qa-integration/pmm_psmdb-pbm_setup/Dockerfile
printf '%s\n' '== mongo shell references =='
rg -n -C 6 'mongo(shell)?|mongos|MONGO|PSMDB|percona-server-mongodb|mongodb-org|mgodatagen' qa-integration/pmm_psmdb-pbm_setup --glob '!*.json'
printf '%s\n' '== repository metadata for image version =='
rg -n -C 4 'REPO|PSMDB|MONGODB|VERSION|TAG' qa-integration/pmm_psmdb-pbm_setup/{Dockerfile,docker-compose-sharded-with-pmm.yaml,.env,Makefile} 2>/dev/null || true

Repository: percona/pmm-qa

Length of output: 50371


🌐 Web query:

MongoDB mongosh sh.moveChunk sh.splitFind helper availability signatures MongoDB 8.0

💡 Result:

In MongoDB 8.0, both sh.moveChunk and sh.splitFind are available as helper methods in mongosh [1][2][3]. sh.moveChunk The signature for this method is sh.moveChunk(namespace, query, destination) [4]. - namespace (string): The full namespace (database.collection) of the sharded collection [4]. - query (document): An equality match on the shard key used to identify the chunk to move [4]. - destination (string): The ID of the recipient shard [4]. This method wraps the moveChunk database command [4]. It is not suitable for hashed shard keys when using the query parameter; for hashed shard keys, users should instead utilize the moveChunk command directly with the bounds field [4][5]. sh.splitFind The signature for this method is sh.splitFind(namespace, query) [6]. - namespace (string): The full namespace of the sharded collection [6][7]. - query (document): A query that identifies the shard key value within the chunk to be split [6][7]. This method splits the identified chunk at its median point, resulting in two roughly equal chunks [6][3]. It wraps the split database command [6][8]. General Note MongoDB documentation emphasizes that in most production environments, automatic chunk management (balancing and splitting) should be left to the built-in system processes rather than manual intervention via these helpers [4][6][7]. Furthermore, while these helpers provide convenience in mongosh, they may not return the same comprehensive information as the underlying database commands [5][8].

Citations:


🌐 Web query:

site:mongodb.com/docs sh.splitFind hashed shard key unsupported

💡 Result:

The sh.splitFind method is not directly supported for splitting chunks in a collection partitioned using a hashed shard key [1][2][3][4]. In MongoDB, while sh.splitFind and sh.splitAt are convenient helpers for manual chunk splitting, they are designed to work with range-based sharding [5][6][7]. For collections using a hashed shard key, you must use the underlying split database command with the bounds parameter [1][2][3][4]. The bounds parameter requires an array containing two documents that specify the exact lower and upper shard-key values of the chunk you intend to split [1][2][3][4]. These values must match the minimum and maximum boundaries of an existing chunk, which can be identified using sh.status [1][2][3][4]. Example of splitting a hashed chunk via the database command: db.adminCommand({ split: "database.collection", bounds: [ { hashed_shard_key: NumberLong("-5838464104018346494") }, { hashed_shard_key: NumberLong("-5557153028469814163") } ] }) [1][2][3][4] Because hashed values are represented as 64-bit integers, you must use the NumberLong type when specifying these bounds [1][2][3][4].

Citations:


Use a range-based shard key for test.test, or use hashed chunk bounds. sharded.json configures { _id: "hashed" }. Therefore, sh.moveChunk() and sh.splitFind() reject these calls. The catch blocks hide each failure, so the loop produces no move or split events. The image’s mongosh shell provides both helpers with the expected signatures.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@qa-integration/pmm_psmdb-pbm_setup/start-sharded-with-pmm.sh` around lines
316 - 325, Update the test.test sharding setup around sh.moveChunk and
sh.splitFind to use bounds compatible with the configured hashed _id shard key,
or change the collection to a range-based shard key. Ensure the moveChunk and
splitFind calls use valid hashed chunk-bound arguments so they execute
successfully, while preserving the existing target iteration and inserted
document flow.

} catch (e) {
print("splitFind failed, skipping: " + e);
}
JSEOF
docker compose -f docker-compose-sharded-with-pmm.yaml exec -T mongos tee /tmp/keep_chunks_moving.sh > /dev/null << 'SHEOF'
#!/bin/bash
while true; do
mongo "mongodb://root:root@localhost" --quiet /tmp/keep_chunks_moving.js > /tmp/keep_chunks_moving.log 2>&1
sleep 240
done
SHEOF
echo "starting background chunk-activity generator"
docker compose -f docker-compose-sharded-with-pmm.yaml exec -d mongos bash /tmp/keep_chunks_moving.sh
Comment on lines +314 to +338

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Use a private temporary directory for generator state.

Lines [314], [330], and [333] use predictable paths under /tmp. If another process in the mongos container can write there, it can pre-create a symlink and redirect tee or shell-redirection writes. Create a mktemp -d directory with mode 700 inside the container and use it for the JavaScript file, shell script, and log.

🧰 Tools
🪛 ast-grep (0.45.1)

[warning] 329-329: Writing to or reading from a hardcoded, predictable path under /tmp is vulnerable to symlink and TOCTOU attacks: a local attacker can pre-create the file (or a symlink pointing elsewhere) and hijack or corrupt the contents. Generate a unique, unpredictable temporary file with mktemp instead, e.g. tmpfile="$(mktemp)" (or mktemp -d for directories) and reference "$tmpfile".
Context: /tmp/keep_chunks_moving.sh
Note: [CWE-377] Insecure Temporary File.

(predictable-tmp-file-bash)


[warning] 337-337: Writing to or reading from a hardcoded, predictable path under /tmp is vulnerable to symlink and TOCTOU attacks: a local attacker can pre-create the file (or a symlink pointing elsewhere) and hijack or corrupt the contents. Generate a unique, unpredictable temporary file with mktemp instead, e.g. tmpfile="$(mktemp)" (or mktemp -d for directories) and reference "$tmpfile".
Context: /tmp/keep_chunks_moving.sh
Note: [CWE-377] Insecure Temporary File.

(predictable-tmp-file-bash)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@qa-integration/pmm_psmdb-pbm_setup/start-sharded-with-pmm.sh` around lines
314 - 338, Update the chunk-activity generator setup around the heredocs and
background launch to create a private mode-700 temporary directory with mktemp
-d inside the mongos container. Use that directory for keep_chunks_moving.js,
keep_chunks_moving.sh, and keep_chunks_moving.log, and update the script
invocation to reference the new private paths instead of predictable /tmp
locations.

Source: Linters/SAST tools


tests=${TESTS:-yes}
if [ $tests != "no" ]; then
echo "running tests"
Expand Down
96 changes: 96 additions & 0 deletions qa-integration/pmm_psmdb-pbm_setup/start-sharded.sh
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,74 @@ docker compose -f docker-compose-sharded.yaml exec -T rscfg01 mongo --quiet << E
EOF
sleep 60
echo
echo "configuring root user on primary rscfg01 configserver replicaset"
docker compose -f docker-compose-sharded.yaml exec -T rscfg01 mongo --quiet << EOF
db.getSiblingDB("admin").createUser({ user: "root", pwd: "root", roles: [ "root", "userAdminAnyDatabase", "clusterAdmin" ] });
EOF
echo
echo "configuring pbm and pmm roles on configserver replicaset rscfg"
docker compose -f docker-compose-sharded.yaml exec -T rscfg01 mongo "mongodb://root:root@localhost/?replicaSet=rscfg" --quiet << EOF
db.getSiblingDB("admin").createRole({
"role": "pbmAnyAction",
"privileges": [{
"resource": { "anyResource": true },
"actions": [ "anyAction" ]
}],
"roles": []
});
db.getSiblingDB("admin").createRole({
role: "explainRole",
privileges: [{
resource: {
db: "",
collection: ""
},
actions: [
"listIndexes",
"listCollections",
"dbStats",
"dbHash",
"collStats",
"find"
]
}],
roles:[]
});
EOF
echo
echo "creating pbm user for configserver replicaset rscfg"
docker compose -f docker-compose-sharded.yaml exec -T rscfg01 mongo "mongodb://root:root@localhost/?replicaSet=rscfg" --quiet << EOF
db.getSiblingDB("admin").createUser({
user: "${pbm_user}",
pwd: "${pbm_pass}",
"roles" : [
{ "db" : "admin", "role" : "readWrite", "collection": "" },
{ "db" : "admin", "role" : "backup" },
{ "db" : "admin", "role" : "clusterMonitor" },
{ "db" : "admin", "role" : "restore" },
{ "db" : "admin", "role" : "pbmAnyAction" }
]
});
EOF
echo
echo "creating pmm user for configserver replicaset rscfg"
docker compose -f docker-compose-sharded.yaml exec -T rscfg01 mongo "mongodb://root:root@localhost/?replicaSet=rscfg" --quiet << EOF
db.getSiblingDB("admin").createUser({
user: "${pmm_mongo_user}",
pwd: "${pmm_mongo_user_pass}",
roles: [
{ role: "explainRole", db: "admin" },
{ role: "clusterMonitor", db: "admin" },
{ role: "read", db: "local" },
{ "db" : "admin", "role" : "readWrite", "collection": "" },
{ "db" : "admin", "role" : "backup" },
{ "db" : "admin", "role" : "clusterMonitor" },
{ "db" : "admin", "role" : "restore" },
{ "db" : "admin", "role" : "pbmAnyAction" }
]
});
EOF
echo
echo "adding shards and creating global mongo user"
docker compose -f docker-compose-sharded.yaml exec -T mongos mongo --quiet << EOF
db.getSiblingDB("admin").createUser({ user: "root", pwd: "root", roles: [ "root", "userAdminAnyDatabase", "clusterAdmin" ] });
Expand Down Expand Up @@ -246,6 +314,34 @@ docker compose -f docker-compose-sharded.yaml exec -T rscfg01 pmm-admin add mong

echo "adding some data"
docker compose -f docker-compose-sharded.yaml exec -T mongos mgodatagen -f /etc/datagen/sharded.json --uri=mongodb://root:root@127.0.0.1:27017

echo "writing chunk-activity generator so the chunk-move/split dashboards keep getting data"
docker compose -f docker-compose-sharded.yaml exec -T mongos tee /tmp/keep_chunks_moving.js > /dev/null << 'JSEOF'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- target script context ---'
sed -n '290,355p' qa-integration/pmm_psmdb-pbm_setup/start-sharded.sh
printf '%s\n' '--- all generated-path references ---'
rg -n -C 3 'keep_chunks_moving|docker compose.*mongos|JSEOF' qa-integration/pmm_psmdb-pbm_setup/start-sharded.sh
printf '%s\n' '--- container user and compose mounts ---'
sed -n '1,180p' qa-integration/pmm_psmdb-pbm_setup/docker-compose-sharded.yaml
printf '%s\n' '--- repository guidance files ---'
find . -maxdepth 3 -type f \( -iname 'README*' -o -iname '*CONTRIBUTING*' -o -iname '*GUIDELINE*' \) -print

Repository: percona/pmm-qa

Length of output: 12651


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- relevant compose services ---'
rg -n -A35 -B8 '^[[:space:]]+mongos:|^[[:space:]]+test:' qa-integration/pmm_psmdb-pbm_setup/docker-compose-sharded.yaml
printf '%s\n' '--- setup documentation ---'
sed -n '1,220p' qa-integration/pmm_psmdb-pbm_setup/readme.md
printf '%s\n' '--- image and privilege declarations ---'
rg -n -C 3 'FROM|USER|privileged|volumes:|mongos|test' qa-integration/pmm_psmdb-pbm_setup/Dockerfile qa-integration/pmm_psmdb-pbm_setup/docker-compose-sharded.yaml
printf '%s\n' '--- script lifecycle and cleanup ---'
sed -n '1,90p' qa-integration/pmm_psmdb-pbm_setup/start-sharded.sh
sed -n '343,390p' qa-integration/pmm_psmdb-pbm_setup/start-sharded.sh

Repository: percona/pmm-qa

Length of output: 44242


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- test image capabilities and Docker access ---'
sed -n '1,220p' qa-integration/pmm_psmdb-pbm_setup/Dockerfile-testinfra
rg -n -C 4 'docker|exec|mongos|keep_chunks|/tmp' qa-integration/pmm_psmdb-pbm_setup/test qa-integration/pmm_psmdb-pbm_setup/*.sh
printf '%s\n' '--- image user declarations ---'
rg -n '^[[:space:]]*USER[[:space:]]|^[[:space:]]*ENTRYPOINT|^[[:space:]]*CMD' qa-integration/pmm_psmdb-pbm_setup/Dockerfile qa-integration/pmm_psmdb-pbm_setup/Dockerfile-testinfra || true
printf '%s\n' '--- deterministic path and symlink check ---'
python3 - <<'PY'
from pathlib import Path
script = Path("qa-integration/pmm_psmdb-pbm_setup/start-sharded.sh").read_text()
compose = Path("qa-integration/pmm_psmdb-pbm_setup/docker-compose-sharded.yaml").read_text()
paths = ["/tmp/keep_chunks_moving.js", "/tmp/keep_chunks_moving.sh", "/tmp/keep_chunks_moving.log"]
print("generated_paths:", paths)
print("all_paths_in_script:", all(p in script for p in paths))
print("mongos_service_privileged:", "  mongos:" in compose and "    privileged: true" in compose[compose.index("  mongos:"):])
mongos = compose[compose.index("  mongos:"):compose.index("  minio:")]
print("mongos_has_tmp_mount:", "/tmp" in mongos)
print("mongos_has_user_override:", any(line.lstrip().startswith("user:") for line in mongos.splitlines()))
# Demonstrate the relevant filesystem property without touching repository files.
import tempfile, os
with tempfile.TemporaryDirectory() as d:
    target = Path(d) / "target"
    link = Path(d) / "fixed-name"
    target.write_text("original")
    link.symlink_to(target)
    with link.open("w") as f:
        f.write("overwritten")
    print("ordinary_writer_follows_precreated_symlink:", target.read_text() == "overwritten")
PY

Repository: percona/pmm-qa

Length of output: 50370


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- focused verifier output ---'
python3 - <<'PY'
from pathlib import Path
script = Path("qa-integration/pmm_psmdb-pbm_setup/start-sharded.sh").read_text()
compose = Path("qa-integration/pmm_psmdb-pbm_setup/docker-compose-sharded.yaml").read_text()
paths = ["/tmp/keep_chunks_moving.js", "/tmp/keep_chunks_moving.sh", "/tmp/keep_chunks_moving.log"]
mongos = compose[compose.index("  mongos:"):compose.index("  minio:")]
print("generated_paths:", all(p in script for p in paths))
print("mongos_privileged:", "    privileged: true" in mongos)
print("mongos_tmp_mount:", "/tmp" in mongos)
print("mongos_user_override:", any(x.lstrip().startswith("user:") for x in mongos.splitlines()))
import tempfile
with tempfile.TemporaryDirectory() as d:
    target, link = Path(d)/"target", Path(d)/"fixed-name"
    target.write_text("original")
    link.symlink_to(target)
    link.write_text("overwritten")
    print("writer_follows_precreated_symlink:", target.read_text() == "overwritten")
PY
printf '%s\n' '--- test sources with Docker or container access ---'
find qa-integration/pmm_psmdb-pbm_setup/test -maxdepth 2 -type f -print
rg -n -C 2 --glob '*.py' 'docker|Docker|exec|mongos|/tmp|subprocess' qa-integration/pmm_psmdb-pbm_setup/test || true

Repository: percona/pmm-qa

Length of output: 3831


Use a private temporary directory for the generator files. tee and shell redirection follow pre-existing symlinks. Create a mktemp -d directory inside mongos, use quoted paths for all three files, and remove it when the background process exits.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@qa-integration/pmm_psmdb-pbm_setup/start-sharded.sh` at line 319, Update the
generator-file setup around the mongos tee command to create a private mktemp -d
directory inside the container, and store all three generated files there using
quoted paths. Ensure the temporary directory is removed when the background
process exits, while preserving the existing generator execution flow.

Source: Linters/SAST tools

var shards = db.getSiblingDB("config").shards.find().toArray().map(function (s) { return s._id; });
var ins = db.getSiblingDB("test").test.insertOne({ ts: new Date() });
shards.forEach(function (target) {
try {
sh.moveChunk("test.test", { _id: ins.insertedId }, target);
} catch (e) {
print("moveChunk to " + target + " failed, skipping: " + e);
}
});
try {
sh.splitFind("test.test", { _id: ins.insertedId });
} catch (e) {
print("splitFind failed, skipping: " + e);
}
Comment on lines +329 to +333

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- target context ---'
sed -n '300,350p' qa-integration/pmm_psmdb-pbm_setup/start-sharded.sh
printf '%s\n' '--- shard-key and split-related references ---'
rg -n -C 3 'splitFind|split|shardCollection|shard key|shardKey|hashed|test\.test' qa-integration/pmm_psmdb-pbm_setup
printf '%s\n' '--- MongoDB image/version declarations ---'
rg -n -i 'mongo.*(image|version)|mongodb|percona-server-mongodb|psmdb' qa-integration/pmm_psmdb-pbm_setup .github docker-compose*.yml 2>/dev/null | head -200

Repository: percona/pmm-qa

Length of output: 35832


🌐 Web query:

MongoDB sh.splitFind hashed shard key find form split command bounds behavior

💡 Result:

In MongoDB, for collections using a hashed shard key, you should not use sh.splitFind to manually split chunks [1][2]. The split command requires the bounds parameter to split chunks in hashed sharded collections, rather than the find parameter used by sh.splitFind [1][2]. The reasons and behavior are as follows: 1. Parameter Mismatch: The sh.splitFind method wraps the split database command using the find parameter [3][4]. However, the documentation for the split command explicitly states that you must use the bounds parameter for collections partitioned using a hashed shard key [1][2]. 2. Bounds Requirement: The bounds parameter requires an array containing two documents that specify the exact minimum and maximum shard-key values of the existing chunk you intend to split [1][2]. These values must match the current chunk's boundaries, which can be identified using sh.status [1][2]. 3. Median Splitting: When the bounds parameter is used correctly, MongoDB splits the chunk along its median [1][2]. The split command cannot use the find or middle parameters for hashed shard keys because hashed shards rely on specific, pre-defined chunk ranges rather than the query-based discovery used by sh.splitFind [1][2]. Attempting to use sh.splitFind on a hashed sharded collection may fail or behave unexpectedly because it is designed for range-based sharding where the query can identify a document within a chunk to determine the split point, which is not applicable to the distribution logic of hashed shard keys [3][1]. To manually split a hashed chunk, you should invoke the split command directly via db.adminCommand using the bounds option [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -eu
python3 - <<'PY'
import json
from pathlib import Path

setup = Path("qa-integration/pmm_psmdb-pbm_setup/start-sharded.sh").read_text()
config = json.loads(Path("qa-integration/pmm_psmdb-pbm_setup/conf/datagen/sharded.json").read_text())

collection = config["collections"][0]
shard_config = collection["shardConfig"]
key = shard_config["key"]

print("collection:", f'{shard_config["shardCollection"]}')
print("shard_key:", key)
print("insert_target_present:", 'getSiblingDB("test").test.insertOne' in setup)
print("splitFind_present:", 'sh.splitFind("test.test", { _id: ins.insertedId })' in setup)
print("catch_logs_and_skips:", 'print("splitFind failed, skipping: " + e);' in setup)
print("hashed_id_for_test.test:", shard_config["shardCollection"] == "test.test" and key == {"_id": "hashed"})
PY

Repository: percona/pmm-qa

Length of output: 285


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- sharded data generator ---'
cat -n qa-integration/pmm_psmdb-pbm_setup/conf/datagen/sharded.json
printf '%s\n' '--- focused consistency check ---'
python3 - <<'PY'
import json
from pathlib import Path

setup = Path("qa-integration/pmm_psmdb-pbm_setup/start-sharded.sh").read_text()
data = json.loads(Path("qa-integration/pmm_psmdb-pbm_setup/conf/datagen/sharded.json").read_text())

matches = []
for item in data:
    shard_config = item.get("shardConfig", {})
    if shard_config.get("shardCollection") == "test.test":
        matches.append((item.get("collection"), shard_config.get("key")))

print("test.test shard configuration:", matches)
print("insert_target_present:", 'getSiblingDB("test").test.insertOne' in setup)
print("splitFind_present:", 'sh.splitFind("test.test", { _id: ins.insertedId })' in setup)
print("failure_is_swallowed:", 'print("splitFind failed, skipping: " + e);' in setup)
PY

Repository: percona/pmm-qa

Length of output: 1163


Use bounds for the hashed-key split.

test.test uses the hashed _id shard key. sh.splitFind() does not support hashed shard keys. Resolve the current chunk bounds and run adminCommand({ split: "test.test", bounds: [...] }); otherwise, the catch logs the failure and no split events reach the dashboard.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@qa-integration/pmm_psmdb-pbm_setup/start-sharded.sh` around lines 329 - 333,
Replace the sh.splitFind call in the hashed-key setup flow with logic that
resolves the current chunk bounds for test.test and invokes adminCommand using
split: "test.test" and those bounds. Preserve the existing failure handling and
ensure the split command executes successfully so split events are emitted.

Source: MCP tools

JSEOF
docker compose -f docker-compose-sharded.yaml exec -T mongos tee /tmp/keep_chunks_moving.sh > /dev/null << 'SHEOF'
#!/bin/bash
while true; do
mongo "mongodb://root:root@localhost" --quiet /tmp/keep_chunks_moving.js > /tmp/keep_chunks_moving.log 2>&1
sleep 240
done
SHEOF
echo "starting background chunk-activity generator"
docker compose -f docker-compose-sharded.yaml exec -d mongos bash /tmp/keep_chunks_moving.sh
Comment on lines +342 to +343

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Install cleanup before launching the detached loop.

The loop starts before the tests, but cleanup runs only after the tests complete. With set -e, any later failure exits before Lines 353-356, leaving the detached process and Compose stack running. Register an EXIT trap before Line 343 and make the trap honor CLEANUP=no.

🧰 Tools
🪛 ast-grep (0.45.1)

[warning] 342-342: Writing to or reading from a hardcoded, predictable path under /tmp is vulnerable to symlink and TOCTOU attacks: a local attacker can pre-create the file (or a symlink pointing elsewhere) and hijack or corrupt the contents. Generate a unique, unpredictable temporary file with mktemp instead, e.g. tmpfile="$(mktemp)" (or mktemp -d for directories) and reference "$tmpfile".
Context: /tmp/keep_chunks_moving.sh
Note: [CWE-377] Insecure Temporary File.

(predictable-tmp-file-bash)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@qa-integration/pmm_psmdb-pbm_setup/start-sharded.sh` around lines 342 - 343,
Register an EXIT cleanup trap before launching the detached
keep_chunks_moving.sh process, using the existing cleanup behavior and honoring
CLEANUP=no. Ensure the trap stops the background generator and Compose stack
even when set -e exits before the current post-test cleanup block, while
preserving normal cleanup behavior.


tests=${TESTS:-yes}
if [ $tests != "no" ]; then
echo "running tests"
Expand Down
Loading