-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Kubernetes pod exec using python client not very interactive #1689
Comments
Can anyone please give any pointer for the solution? |
In my opinion, the exec implementation has serious deficiencies. The one time I needed to perform exec's, I implemented my own handling of it. Here is the method I created, use and modify at your own risk: def exec(self, *command, stdin=None, progress_at_start=None, filter_initial_startswith=None):
if progress_at_start:
print(f"{progress_at_start}...", end='', flush=True)
progress_at_start = time.time()
wssock = kubernetes.stream.stream(
self.core_api.connect_get_namespaced_pod_exec,
self.jenkins,
self.namespace,
command=list(command),
stdin=stdin is not None,
tty=False,
stdout=True,
stderr=True,
_preload_content=False,
).sock
rlist = [wssock.sock]
stdin_channel = bytes([kubernetes.stream.ws_client.STDIN_CHANNEL])
stdout_channel = kubernetes.stream.ws_client.STDOUT_CHANNEL
stderr_channel = kubernetes.stream.ws_client.STDERR_CHANNEL
if isinstance(stdin, str):
stdin = stdin.encode('utf-8')
if isinstance(stdin, bytes):
wssock.send(stdin_channel + stdin, websocket.ABNF.OPCODE_BINARY)
stdin = None
if stdin is not None:
if not isinstance(stdin, int):
print(file=sys.stderr)
print(f"Unexpected stdin argument: {stdin}", file=sys.stderr)
print(file=sys.stderr, flush=True)
sys.exit(1)
rlist.append(stdin)
stdout = sys.stdout.fileno()
stderr = sys.stderr.fileno()
if isinstance(filter_initial_startswith, str):
filter_initial_startswith = filter_initial_startswith.encode('utf-8')
while True:
rs, _ws, _xs = select.select(rlist, [], [], 1 if progress_at_start else None)
if progress_at_start:
now = time.time()
if now - progress_at_start >= 1:
os.write(stdout, b'.')
progress_at_start = now
if stdin in rs:
data = os.read(stdin, 32 * 1024)
if len(data) == 0:
rlist.remove(stdin)
else:
wssock.send(stdin_channel + data, websocket.ABNF.OPCODE_BINARY)
if wssock.sock in rs:
opcode, frame = wssock.recv_data_frame(True)
if opcode == websocket.ABNF.OPCODE_CLOSE:
rlist.remove(wssock.sock)
elif opcode == websocket.ABNF.OPCODE_BINARY:
channel = frame.data[0]
data = frame.data[1:]
if channel in (stdout_channel, stderr_channel):
if filter_initial_startswith:
if len(data):
data = data.split(b'\n')
while len(data) and data[0].startswith(filter_initial_startswith):
del data[0]
if len(data):
filter_initial_startswith = None
data = b'\n'.join(data)
else:
data = b''
if len(data):
if progress_at_start:
os.write(stdout, b'\n')
progress_at_start = None
if channel == stdout_channel:
os.write(stdout, data)
else:
os.write(stderr, data)
elif channel == kubernetes.stream.ws_client.ERROR_CHANNEL:
if progress_at_start:
os.write(stdout, b'\n')
wssock.close()
error = json.loads(data)
if error['status'] == 'Success':
return 0
if error['reason'] == 'NonZeroExitCode':
for cause in error['details']['causes']:
if cause['reason'] == 'ExitCode':
return int(cause['message'])
print(file=sys.stderr)
print(f"Failure running: {' '.join(command)}", file=sys.stderr)
print(f"Status: {error['status']} - Message: {error['message']}", file=sys.stderr)
print(file=sys.stderr, flush=True)
sys.exit(1)
else:
if progress_at_start:
os.write(stdout, b'\n')
print(file=sys.stderr)
print(f"Unexpected channel: {channel}", file=sys.stderr)
print(f"Data: {data}", file=sys.stderr)
print(file=sys.stderr, flush=True)
sys.exit(1)
else:
if progress_at_start:
os.write(stdout, b'\n')
print(file=sys.stderr)
print(f"Unexpected websocket opcode: {opcode}", file=sys.stderr)
print(file=sys.stderr, flush=True)
sys.exit(1) |
Thanks a lot for the reply. This code still misses the piece of interactive terminal experience. For example, if I set tty=True and stdin=True and run this code the terminal that I get does not allow arrow keys and instead shows |
The control codes issue has nothing to do with this python kubernetes client. The python |
Yeah, everything described here is how https://docs.python.org/3/library/functions.html#input works, and has nothing to do with kubernetes or this library. You can reproduce the observed behaviour locally with
Fancy editor history behaviour (eg up arrow) can be achieved in two ways:
|
Thanks, @ellieayla, and @iciclespider. Using https://docs.python.org/3/library/cmd.html locally and sending commands ['/bin/sh', '-c', 'command'] to the remote shell one by one will do the trick for arrow keys. |
This also has nothing to do with kubernetes, python, or the kubernetes client. That is just how running programs locally that interact with a remote server work. Sounds like you need to take some basic programming courses. |
cc @yliaog |
The Kubernetes project currently lacks enough contributors to adequately respond to all issues and PRs. This bot triages issues and PRs according to the following rules:
You can:
Please send feedback to sig-contributor-experience at kubernetes/community. /lifecycle stale |
The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs. This bot triages issues and PRs according to the following rules:
You can:
Please send feedback to sig-contributor-experience at kubernetes/community. /lifecycle rotten |
The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs. This bot triages issues and PRs according to the following rules:
You can:
Please send feedback to sig-contributor-experience at kubernetes/community. /close |
@k8s-triage-robot: Closing this issue. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
What happened:
I am following the official example to exec into a Kubernetes container using the python Kubernetes-client library.
The above code is able to exec into the container. However, the shell is not very interactive. The issues with it are:-
Arrow keys do not work. When pressing arrow keys, exec shows
^[[D^[[C^[[A^[[B
charactersTab auto-complete does not work. When I press tab character, it takes tab as input white spaces instead of auto-completing.
I have to hit the enter key twice to get the command output. Example:-
Is there anything wrong with the code or is there any better way to exec into the container?
How to reproduce it (as minimally and precisely as possible):
Environment:
kubectl version
) :MacOS Big Slur v11.6
Python 3.9.10
pip list | grep kubernetes
) :kubernetes 21.7.0
The text was updated successfully, but these errors were encountered: