web-dev-qa-db-fra.com

Abuser cURL pour communiquer avec Redis

Je veux envoyer un PING à Redis pour vérifier si la connexion fonctionne, je peux maintenant installer redis-cli, mais je ne le veux pas et curl est déjà là. Alors, comment puis-je abuser de curl pour le faire? En gros, je dois désactiver ce qui est envoyé ici:

> GET / HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: localhost:6379
> Accept: */*
> 
-ERR wrong number of arguments for 'get' command
-ERR unknown command 'User-Agent:'
-ERR unknown command 'Host:'
-ERR unknown command 'Accept:'

J'ai pu supprimer le User-Agent complètement en ajoutant -A "", mais je ne trouve rien d'autre pour le reste. Une idée de comment je peux faire ça?

16
Mahoni

Lorsque vous souhaitez utiliser Curl, vous avez besoin de REST sur un REEE, tel que webdis, tinywebdis ou turbowebdis. Voir https://github.com/markuman/tinywebdis#turbowebdis-tinywebdis--cherrywebdis

$ curl -w '\n' http://127.0.0.1:8888/ping
{"ping":"PONG"}

Sans interface REST pour redis, vous pouvez utiliser netcat par exemple.

$ (printf "PING\r\n";) | nc localhost 6379 
+PONG

Avec netcat, vous devez créer vous-même le protocole relatif aux REEE. Voir http://redis.io/topics/protocol

mise à jour 2018-01-09

J'ai construit une fonction bash puissante qui pique l'instance de Redis à tout prix sur TCP

    function redis-ping() {
            # ping a redis server at any cost
            redis-cli -h $1 ping 2>/dev/null || \
                    echo $((printf "PING\r\n";) | nc $1 6379 2>/dev/null || \
                    exec 3<>/dev/tcp/$1/6379 && echo -e "PING\r\n" >&3 && head -c 7 <&3)
    }

utilisation redis-ping localhost

29
Markus

Pas curl, mais ne nécessite pas d'interface HTTP ou nc (idéal pour quelque chose comme un conteneur sur lequel nc n'est pas installé)

exec 3<>/dev/tcp/127.0.0.1/6379 && echo -e "PING\r\n" >&3 && head -c 7 <&3

Devrait vous donner

+PONG

Vous pouvez en savoir plus sur ce qui se passe dans cet article fantastique .

27
Joel B

J'avais besoin d'ajouter un sommeil au nc fourni par @Markus pour le faire fonctionner à partir d'un système distant:

(printf "PING\r\n"; sleep 1) | nc remote.redis.hostname 6379

Voir Protocoles de demande/réponse et RTT: Redis Pipelining pour plus de détails.

14
Peter M

En élaborant sur l'excellente réponse de @Joel B. J'avais besoin de cela dans un script Shell dans le conteneur Docker, sans boucle, sans redis-cli ni nc .... Le REDIS que je teste est la carte publique Redis-ha Helm pour kubernetes à partir d'ici: https : //github.com/helm/charts/tree/master/stable/redis-ha

Les variables à définir sont:

  • REDIS_Host = Nom d'hôte (adresse DNS ou IP) contenant le maître Redis et sentinel (divisez cela en hôtes séparés s'ils sont séparés, et changez les ports si vous en avez besoin - mais dans le tableau de bord, le maître/esclave et sentinel sont dans le même pod et utilisent les ports standard)

  • REDIS_STARTUP_TIMEOUT = secondes maximum à attendre avant d'abandonner - valeur par défaut à 10 minutes

  • REDIS_STARTUP_RETRY = secondes à attendre entre les tests - 15 secondes par défaut

  • DEBUG = définir ceci à true pour faire écho aux réponses ayant échoué

Les subtilités de la technique sont décrites dans les commentaires (je vous suggère de garder les commentaires en place pour sauver vos collègues - et votre futur - de certaines folies lorsque vous essayez de déchiffrer les chevrons).

# wait for 10 mins and check again every 15 seconds
let n=${REDIS_STARTUP_TIMEOUT:-600}
let m=${REDIS_STARTUP_RETRY:-15}
ready=false
while ((n > 0)); do
    # These scripts are the best way to check if redis is running without having access to nc, curl or redis-cli
    # They write a "PING" to the redis and sentinel ports on the hostname "dc-ecm-redis-ha"
    # and look for a "PONG+" in return.
    #
    # Detailed explanation:
    # -  3<>/dev/tcp... opens a file handle identified as #3 for input and output on the tcp Host and port
    #    The Host $REDIS_Host is defined in DNS by the Kubernetes _service_, and the port is for redis or sentinel
    #    (Uses linux's low-level network-as-filesystem support. Think of it as a sort of poor-man's telnet)
    # -  "PING" followed by carriage-return is sent to the port by redirecting to the handle with >&3
    # -  The response from the port is sent to the head command with <&3
    # -  The first 5 bytes of the response are captured with -c 5. This removes the linebreak (\r) from the response
    # -  Standard Shell $() around the whole thing stores the result in a variable (master or sentinel)
    # -  When Redis is NOT ready, the result is generally a failure in the exec or some other error, which goes
    #    to stderr, so we wrap it in  { } > 2>&1 to capture that error in the variable too.
    # -  Success is measured by "+PONG" being in the variable
    # -  If you set the variable DEBUG to "true" (or "TRUE" -> the {,,} lower-cases it) the failed responses are echoed
    # -  (There are easier ways to do this if you have redis-cli installed or nc, but typically you don't on a docker container)
    # -  The whole thing waits n seconds for Redis to be ready, checking every m seconds
    #
    master=$( { exec 3<>/dev/tcp/${REDIS_Host}/6379 && echo -e "PING\r\n" >&3 && head -c 5 <&3; } 2>&1 )
    sentinel=$( { exec 3<>/dev/tcp/${REDIS_Host}/26379 && echo -e "PING\r\n" >&3 && head -c 5 <&3; } 2>&1 )
    if [ "$sentinel" = "+PONG" -a "$master" = "+PONG" ]; then ready=true;
       break;
   else echo "$(date) : Waiting $n more seconds for Redis master and sentinel to respond to PING"
        [[ "${DEBUG,,}" = "true" ]] && echo "master response was [$master]";
        [[ "${DEBUG,,}" = "true" ]] && echo "sentinel response was [$sentinel]";
        sleep $m
        ((n-=m))
    fi
done

if [ "$ready" = true ]
    then echo "$(date) : REDIS is ready"
    # do something when Redis is ready
else
    echo "$(date) : ERROR: REDIS is still not ready. Giving up waiting"
    # do something when Redis fails
fi
0
Rhubarb