2

I have a repetitive task that I do while testing which entails connecting to a cassandra pod and running a couple of CQL queries.

Here's the "manual" approach:

  1. On cluster controller node, I exec a shell on the pod using kubectl:
    kubectl exec pod/my-app-cassandra-pod-name -it --namespace myns -- /bin/bash

  2. Once in the pod I execute cqlsh:
    cqlsh $(hostname -i) -u myuser
    and then enter password interactively

  3. I execute my cql queries interactively

Now, I'd like to have a bash script to automate this. My intent is to run cqlsh directly, via kubectl exec.

The problem I have is that apparently I cannot use a shell variable within the "command" section of kubectl exec. And I will need shell variables to store a) the pod's IP, b) an id which is the input to my first query, and c) intermediate query results (the two latter ones are not added to script yet).

Here's what I have so far, using a dummy CQL query for now:

#!/bin/bash

CASS_IP=$(kubectl exec pod/my-app-cassandra-pod-name -it --namespace myns -- /usr/bin/hostname -i)
echo $CASS_IP   # This prints out the IP address just fine, say 192.168.79.208

# The below does not work, errors provided below
kubectl exec pod/my-app-cassandra-pod-name -it --namespace myns -- /opt/cassandra/bin/cqlsh $CASS_IP -u myuser -p 'mypass' -e 'SELECT now() FROM system.local;'

# The below works just fine and returns the CQL query output
kubectl exec pod/my-app-cassandra-pod-name -it --namespace myns -- /opt/cassandra/bin/cqlsh 192.168.79.208 -u myuser -p 'mypass' -e 'SELECT now() FROM system.local;'

The output from the above is as follows, where IP is echoed, first exec'd cqlsh breaks, and second succeeds:

192.168.79.208
Warning: Timezone defined and 'pytz' module for timezone conversion not installed. Timestamps will be displayed in UTC timezone.

Traceback (most recent call last):
  File "/opt/cassandra/bin/cqlsh.py", line 2357, in <module>
    main(*read_options(sys.argv[1:], os.environ))
  File "/opt/cassandra/bin/cqlsh.py", line 2326, in main
    encoding=options.encoding)
  File "/opt/cassandra/bin/cqlsh.py", line 463, in __init__
    load_balancing_policy=WhiteListRoundRobinPolicy([self.hostname]),
  File "/opt/cassandra/bin/../lib/cassandra-driver-internal-only-3.25.0.zip/cassandra-driver-3.25.0/cassandra/policies.py", line 425, in __init__
  File "/opt/cassandra/bin/../lib/cassandra-driver-internal-only-3.25.0.zip/cassandra-driver-3.25.0/cassandra/policies.py", line 426, in <listcomp>
  File "/usr/lib64/python3.6/socket.py", line 745, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -2] Name or service not known
command terminated with exit code 1
Warning: Timezone defined and 'pytz' module for timezone conversion not installed. Timestamps will be displayed in UTC timezone.


 system.now()
--------------------------------------
 e78e75c0-0d3e-11ed-8825-1de1a1b1c128

(1 rows)

Any ideas how to get around this? I've been researching this for quite a while now, but I'm stuck...

4
  • 1
    A friendly reminder that Stack Overflow is for getting help with coding, algorithm, or programming language problems. For future reference, you should post DB admin/ops questions on dba.stackexchange.com/questions/ask?tags=cassandra. If you post it there, I'd be happy to help. Cheers! Commented Jul 27, 2022 at 0:41
  • Apologies... it's been a while since I asked a question here. But wouldn't this fit under shell scripting? Anyways, I see your point. Commented Jul 27, 2022 at 3:46
  • I followed your advice Erick, and I have posted it to dba.stackexchange.com. Commented Jul 27, 2022 at 4:13
  • Awesome! I've responded to you in dba.stackexchange.com/questions/314892. Cheers! Commented Jul 27, 2022 at 8:46

1 Answer 1

7

This is a very, very FAQ: the kubectl exec is, as its name says, using exec(3) versus system(3) -- which in your case wouldn't work anyway because the $ in your kubectl exec would be interpreted by your shell not the pod's shell

but thankfully the solution is the same to both problems: create your own system(3) by wrapping the command in a sh -c invocation (or bash -c if you have bash-isms and bash is available inside the pod):

kubectl exec pod/my-app-cassandra-pod-name -it --namespace myns -- sh -c '/opt/cassandra/bin/cqlsh $(hostname -i) -u myuser -p "mypass" -e "SELECT now() FROM system.local;"'

as always, be cognizant of the "outer" versus "inner" quoting, especially if your "mypass" or the -e statement contains shell meta-characters

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, that worked nicely. Although the intention to be able to use shell variables was so that I could save the output from one query, maybe massage it a bit (awk, etc) and store it to a shell variable to be able to use it as input to a subsequent query. Nesting that sequence one within the other will get pretty ugly, pretty quick. :-D But from your answer, I guess that won't be possible...
It's possible, it just requires good quoting skills, or copying a locally written script to the pod via kubectl cp and then executing it, or using something like ansible -c kubectl -m raw ... to let them do the quoting for you
Another observation is that (depending on the size of the query results) you may be happier with kubectl port-forward to use your local tooling against the in-cluster cassandra
Thanks... I was actually going down the path you mentioned in your first comment: build the script outside of the pod, then push it to pod and then execute it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.