Skip to content
Merged
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
5 changes: 5 additions & 0 deletions example/redis/distros/deploy-distros.sh
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,13 @@ bind_valkey() { apply_cp valkey cp-valkey.yaml; label_sts valkey valkey-primary
bind_keydb() { apply_cp keydb cp-keydb.yaml; label_sts keydb keydb keydb; }
bind_dragonfly() {
apply_cp dragonfly cp-dragonfly.yaml
# The operator only stamps podMetadata onto NEWLY created pods — a live patch does
# not relabel the running instance, so node-agent never switches to the profile.
# Patch the CR, then recreate the instance pod so it is born with the label.
kubectl -n dragonfly patch dragonfly dragonfly --type merge \
-p '{"spec":{"podMetadata":{"labels":{"kubescape.io/user-defined-profile":"dragonfly"}}}}'
kubectl -n dragonfly delete pod dragonfly-0 --ignore-not-found
kubectl -n dragonfly wait --for=condition=ready pod/dragonfly-0 --timeout=120s
Comment on lines +86 to +87

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 | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file excerpt =="
sed -n '1,170p' example/redis/distros/deploy-distros.sh

echo
echo "== nearby occurrences of kubectl wait/delete =="
rg -n "kubectl .*delete|kubectl .*wait|dragonfly-0" example/redis/distros/deploy-distros.sh || true

echo
echo "== changed diff around file if available =="
git diff -- example/redis/distros/deploy-distros.sh | sed -n '1,180p'

Repository: k8sstormcenter/bob

Length of output: 5095


🌐 Web query:

kubectl wait --for=create Pod documentation

💡 Result:

The kubectl wait command supports waiting for a resource to be created using the --for=create flag [1][2]. When you execute kubectl wait --for=create [resource_type]/[resource_name], the command will pause and poll the Kubernetes API until the specified resource exists [1][3]. If the resource is already present, the command proceeds immediately to check any other conditions specified [1][3]. Key points regarding this functionality: - Combined Conditions: You can combine creation and status checks in a single command. For example, to wait for a pod to be created and then reach a Ready state, you can use: kubectl wait --for=create pod/my-pod --for=condition=Ready pod/my-pod [1][3] - Sequential Evaluation: If --for=create is included alongside other conditions, the creation check is performed first [1][4][5]. - Behavior: This is an efficient way to handle scenarios where a resource is created asynchronously (e.g., by a deployment, job, or external process) and you need your script or process to pause until the resource is available to be acted upon [1][3]. Please note that in modern versions of Kubernetes (as of 2026), kubectl wait generally attempts to handle resource existence gracefully, but explicitly using --for=create is the documented method for ensuring the tool waits for the resource to be registered in the API server before evaluating further conditions [1][6].

Citations:


🌐 Web query:

kubectl kubectl wait condition Ready when object does not exist NotFound

💡 Result:

When using the kubectl wait command, if the target resource does not exist, the command will exit immediately with a non-zero exit status and an error, typically "Error from server (NotFound)" or "no matching resources found" [1][2][3]. It does not natively block or poll until the resource is created [1][3]. To address this behavior, you can use the following approaches: 1. Recommended: Use a wrapper script or a loop. Before calling kubectl wait, implement a loop to poll for the existence of the resource (e.g., using kubectl get). Once the resource is confirmed to exist, run kubectl wait to poll for the desired condition [1][3]. 2. Use --for=create (When supported). In some contexts, you may be able to use the --for=create flag in conjunction with other conditions to explicitly wait for the resource to be created before checking for readiness [4]. Example command: kubectl wait --for=create pod/my-pod --timeout=30s kubectl wait --for=condition=Ready pod/my-pod --timeout=120s 3. Alternative: Use kubectl rollout status. If you are waiting for a Deployment, StatefulSet, or DaemonSet, kubectl rollout status is often more robust than kubectl wait for handling resources that may not yet exist or are in the process of rolling out [3]. Example command: kubectl rollout status deployment/my-deployment --timeout=120s Historically, this behavior has been a known limitation in kubectl wait, where it was intentionally designed to fail if the resource was missing rather than block indefinitely [2][5]. While there have been ongoing community discussions and proposals to add native support for waiting for resource creation (e.g., --wait-for-creation flags), the most reliable, production-tested method remains explicit polling or using resource-specific rollout commands [6][7][8].

Citations:


Wait for the replacement pod before checking readiness.

kubectl wait --for=condition=ready does not block until the pod is created; if dragonfly-0 is deleted before the StatefulSet recreates it, the wait can fail with NotFound. Add an explicit creation wait or poll the pod for existence before checking the ready condition.

Suggested ordering
  kubectl -n dragonfly delete pod dragonfly-0 --ignore-not-found
+ kubectl -n dragonfly wait --for=create pod/dragonfly-0 --timeout=120s
  kubectl -n dragonfly wait --for=condition=ready pod/dragonfly-0 --timeout=120s
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
kubectl -n dragonfly delete pod dragonfly-0 --ignore-not-found
kubectl -n dragonfly wait --for=condition=ready pod/dragonfly-0 --timeout=120s
kubectl -n dragonfly delete pod dragonfly-0 --ignore-not-found
kubectl -n dragonfly wait --for=create pod/dragonfly-0 --timeout=120s
kubectl -n dragonfly wait --for=condition=ready pod/dragonfly-0 --timeout=120s
🤖 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 `@example/redis/distros/deploy-distros.sh` around lines 86 - 87, Update the pod
replacement flow in the deployment script after deleting dragonfly-0 to
explicitly wait or poll until the StatefulSet recreates the pod, then run the
existing kubectl wait for its ready condition. Preserve the current namespace,
pod name, ignore-not-found deletion, and timeout behavior.

}

do_distro() { # deploy-fn bind-fn
Expand Down
9 changes: 3 additions & 6 deletions example/redis/distros/functional/dragonfly.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ tests:
- {name: time, redis: {command: ["TIME"]}}
- {name: dbsize, redis: {command: ["DBSIZE"]}}
- {name: slowlog-get, redis: {command: ["SLOWLOG", "GET", "10"]}}
- {name: memory-doctor, redis: {command: ["MEMORY", "DOCTOR"]}}

# ── Strings + expiry variants ─────────────────────────────────────────────
- {name: set, redis: {command: ["SET", "s:k", "hello"], expectedReply: "OK"}}
Expand Down Expand Up @@ -104,8 +103,9 @@ tests:
- {name: eval, redis: {command: ["EVAL", "return redis.call('SET', KEYS[1], ARGV[1])", "1", "lua:k", "luaval"]}}
- {name: eval-compute, redis: {command: ["EVAL", "local t=0 for i=1,100 do t=t+i end return t", "0"]}}
- {name: script-load, redis: {command: ["SCRIPT", "LOAD", "return 1"]}}
- {name: function-list, redis: {command: ["FUNCTION", "LIST"]}}
- {name: function-stats,redis: {command: ["FUNCTION", "STATS"]}}
# dragonfly (v1.39) implements a Redis SUBSET: FUNCTION (Redis 7 server-side
# functions), OBJECT, MEMORY DOCTOR and CONFIG SET appendonly are unsupported,
# so those tests are omitted here (they remain in the redis-oss/valkey suites).
Comment on lines +106 to +108

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the Dragonfly suite description to match the tests.

The metadata description at Lines 5-12 still claims full behavior coverage, including BGREWRITEAOF and CONFIG SET appendonly yes. The Dragonfly suite now omits those paths and retains only BGSAVE and LASTSAVE in the persistence section. This text can mislead users about the learned profile coverage.

🤖 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 `@example/redis/distros/functional/dragonfly.yaml` around lines 106 - 108,
Update the Dragonfly suite metadata description near the top of the YAML to
remove claims of BGREWRITEAOF and CONFIG SET appendonly coverage, and describe
the persistence coverage as only BGSAVE and LASTSAVE. Keep the description
aligned with the omitted tests documented in the suite.


# NOTE: MULTI/EXEC transactions and SUBSCRIBE/MONITOR/blocking ops are omitted —
# bobctl's RESP client opens a fresh RESP2 connection per test, so multi-command
Expand All @@ -122,7 +122,6 @@ tests:
- {name: ttl, redis: {command: ["TTL", "s:k"]}}
- {name: persist, redis: {command: ["PERSIST", "s:k"]}}
- {name: type, redis: {command: ["TYPE", "z:lb"]}}
- {name: object-encoding, redis: {command: ["OBJECT", "ENCODING", "z:lb"]}}
- {name: copy, redis: {command: ["COPY", "s:k", "s:kcopy"]}}
- {name: scan, redis: {command: ["SCAN", "0", "COUNT", "100"]}}
- {name: randomkey, redis: {command: ["RANDOMKEY"]}}
Expand All @@ -131,8 +130,6 @@ tests:
# ── Persistence — the fork-triggering paths (key for a realistic profile) ──
- {name: bgsave, redis: {command: ["BGSAVE", "SCHEDULE"]}}
- {name: lastsave, redis: {command: ["LASTSAVE"]}}
- {name: config-aof-on, redis: {command: ["CONFIG", "SET", "appendonly", "yes"], expectedReply: "OK"}}
- {name: config-aof-off, redis: {command: ["CONFIG", "SET", "appendonly", "no"]}}

# ── Cleanup ───────────────────────────────────────────────────────────────
- {name: unlink, redis: {command: ["UNLINK", "s:kcopy", "l:q2", "set:u", "z:dst"]}}
6 changes: 3 additions & 3 deletions example/redis/distros/functional/keydb.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ tests:
- {name: xinfo, redis: {command: ["XINFO", "STREAM", "st:s"]}}
- {name: xtrim, redis: {command: ["XTRIM", "st:s", "MAXLEN", "100"]}}

# ── Scripting (Lua) + functions ───────────────────────────────────────────
# ── Scripting (Lua) ─────────────────────────────────────────────────────────
# keydb 6.x is Redis-6-based: FUNCTION (Redis 7.0 server-side functions) is not
# implemented, so only EVAL/SCRIPT are exercised here.
- {name: eval, redis: {command: ["EVAL", "return redis.call('SET', KEYS[1], ARGV[1])", "1", "lua:k", "luaval"]}}
- {name: eval-compute, redis: {command: ["EVAL", "local t=0 for i=1,100 do t=t+i end return t", "0"]}}
- {name: script-load, redis: {command: ["SCRIPT", "LOAD", "return 1"]}}
- {name: function-list, redis: {command: ["FUNCTION", "LIST"]}}
- {name: function-stats,redis: {command: ["FUNCTION", "STATS"]}}

# NOTE: MULTI/EXEC transactions and SUBSCRIBE/MONITOR/blocking ops are omitted —
# bobctl's RESP client opens a fresh RESP2 connection per test, so multi-command
Expand Down
Loading