Unable to exec command into kubernetes pod - python

Python version 3.8.10
Kubernetes version 23.3.0
I'm trying to run a command into a specific pod in kubernetes using python. I've tried to reduce the code as much as I could, so I'm running this.
from kubernetes import client, config
config.load_kube_config()
v1 = client.CoreV1Api()
response = v1.connect_get_namespaced_pod_exec(pod_name , namespace, command="df -h", stderr=True, stdin=True, stdout=True, tty=True)
print(response)
But it's not working. I'm getting this response.
kubernetes.client.exceptions.ApiException: (400)
Reason: Bad Request
HTTP response headers: HTTPHeaderDict({'Audit-Id': '511c23ce-03bb-4b52-a559-3f354fc80235', 'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 18 Mar 2022 18:06:11 GMT', 'Content-Length': '139'})
HTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Upgrade request required","reason":"BadRequest","code":400}
If I run typical example of list all pods . It's working fine. So, it should not be a configuration issue. I've read about this problem in the past here and here. But I assume it cannot be that, due to they are closed issues.
If I run k9s shell request, I can connect with pod with no problem. This is what I see in ps a when I'm doing this /usr/bin/kubectl --context gke_cloudpak_europe-west2-xxxxx exec -it -n namespace_name pod_name -c rt -- sh -c command -v bash >/dev/null && exec bash || exec sh
Another update, I've found this info. At last of page there is a paragraph with says.
Why Exec/Attach calls doesn’t work
Starting from 4.0 release, we do not support directly calling exec or attach calls. you should use stream module to call them. so instead of resp = api.connect_get_namespaced_pod_exec(name, ... you should call resp = stream(api.connect_get_namespaced_pod_exec, name, ....
Using Stream will overwrite the requests protocol in core_v1_api.CoreV1Api() This will cause a failure in non-exec/attach calls. If you reuse your api client object, you will need to recreate it between api calls that use stream and other api calls.
I've tried to do it in this way, but same result :(
Any idea about what I'm doing wrong?
Thanks a lot for your help.
Regards

Yes, this official guide says that you should use resp = **stream**(api.connect_get_namespaced_pod_exec(name, ... instead.
So you have to edit your code like this:
...
from kubernetes.stream import stream
...
v1 = client.CoreV1Api()
response = stream(v1.connect_get_namespaced_pod_exec, pod_name , namespace, command="df -h", stderr=True, stdin=True, stdout=True, tty=True)
print(response)

Related

download password protected file from owncloud with python

How can I download a password protected file inside python?
The file is shared via Owncloud and the access is protected with a password by Owncloud.
I know it works with curl by using:
curl -u "FileId:FilePw" -H 'X-Requested-With: XMLHttpRequest' "https://exampledomain.com/public.php/webdav/" >output_file
The field file id FileId is extracted from the shared link.
There are web pages which can convert curl command to many different languages and modules - even to Python and requests - ie. Curl Converter
import requests
headers = {
'X-Requested-With': 'XMLHttpRequest',
}
response = requests.get('https://exampledomain.com/public.php/webdav/',
headers=headers,
auth=('FileId', 'FilePw'))
And this needs only to save response in binary mode
with open('filename.ext', 'wb') as fh:
fh.write( response.content )
You can nest the command into a system call with os module
system_object = os.system('your command')
or fork a new process and use the subprocess run
myProcess = subprocess.run()
requests module allows you to use http commands
import requests
headers = {}
response = requests.method(params)
the important part is that you assign an object variable to the instance method so that you can work with the file object

Error: Unauthorized - Python script to IBM Watson Visual Recognition

So I'm trying to get the output of the IBM Visual Recognition Service, but always get the same Error: {"code":401, "error": "Unauthorized"}
It works if I try it with cURL:
$ curl -X POST -u "apikey: ------------" -F "images_file=#bobross.jpg" "https://gateway.watsonplatform.net/visual-recognition/api/v3/detect_faces?version=2018-03-19"
{ facerecognition data }
My python code so far:
import json
import sys
import requests
header= { 'apikey': '---------', 'Content-Type': 'FaceCharacteristics'}
url= "https://gateway.watsonplatform.net/visual-recognition/api/v3/detect_faces?version=2018-03-19"
file ={image:open('bobross.jpg','rb')}
r = requests.post(url, headers=header, files=file)
print(r.text)
I tried my code in other variants, but it always led to "Unauthorized".
Btw, I am very little experienced with python, I'm still trying to learn.
In your curl example you are passing authentication with the -u flag while in python you are passing it in the header as is. The server is ignoring the authentication in the header and you are being returned a 401 as we expect.
To make life easier we can pass our auth details into the request itself with
auth=('apikey', '[An API Key]') as a named parameter.
It would also be worth removing the Content-Type: FaceCharacteristics from the header - not really sure where this was picked up.
import requests
url = 'https://gateway.watsonplatform.net/visual-recognition/api/v3/classify?version=2018-03-19'
files = {'images_file': open('fruitbowl.jpg','rb')}
resp = requests.post(url, auth=('apikey', '[An API Key]'), files=files)
print(resp.content)
Finally add the file and you should be all set.
More info on requests here
However if you are doing anything more than this..
You probably want to have a look at the Python SDK that IBM provides.
It has more documentation and sample code that you can use.
For example, this is provided.
import json
from watson_developer_cloud import VisualRecognitionV3
visual_recognition = = VisualRecognitionV3(
version='{version}',
api_key='{api_key}'
)
with open('./fruitbowl.jpg', 'rb') as images_file:
classes = visual_recognition.classify(
images_file,
threshold='0.6',
classifier_ids='dogsx2018x03x17_1725181949,Connectors_424118776')
print(json.dumps(classes, indent=2))

Curl works but python requests doesn't

When I do curl, I get a response:
root#3d7044bac92f:/home/app/tmp# curl -H "Content-type: application/json" -X GET https://github.com/timeline.json -k
{"message":"Hello there, wayfaring stranger. If you\u2019re reading this then you probably didn\u2019t see our blog post a couple of years back announcing that this API would go away: http://git.io/17AROg Fear not, you should be able to get what you need from the shiny new Events API instead.","documentation_url":"https://developer.github.com/v3/activity/events/#list-public-events"}
However, when I do python requests to the same URL I get a status 410.
import requests
headers = {
'Content-type': 'application/json',
}
r = requests.get('https://github.com/timeline.json')
print r.json
root#3d7044bac92f:/home/app/tmp# python rest.py
<bound method Response.json of <Response [410]>>
What gives?
The host is a standard Ubuntu docker image and only installed Curl and some python modules. Python -V is 2.7
Note: I looked at this question but I can't telnet into above server so that solution doesn't apply to me:
Curl works but not Python requests
You've made at least two errors in your program.
1) You haven't specified the data= or headers parameters to the requests.get() call. Try this:
r = requests.get('https://github.com/timeline.json', data=data, headers=headers)
2) .json is a method, not a data attribute of the response object. As a method, it must be called in order to be effective. Try this:
print r.json()

ReadTheDocs set version to active via script

I am trying to set ReadTheDocs.com (i.e. the commercial end of ReadTheDocs) versions' active state programatically.
This idea being that a branch, when created, has documentation built for it, and when the branch ends we delete the version documentation (or at least stop building for it).
The latter is, obviously, only cleanup and not that important (want, not need). But we'd strongly like to avoid having to use the project management interface to set each branch/version to active.
I've been trying to use the v2 REST API provided by RTD. I can extract version data from "GET https://readthedocs.com/api/v2/version/" and find the version I want to mess with, but I am unable to either send data back, or find something that lets me set Version.active=True for a given version id in their API.
I'm not hugely up on how to play with these APIs so any help would be much appreciated.
I am using python and the requests library.
I searched a solution for this, because I had the same problem at automating the build process of the documentation in connection with my Git server.
At the end I found two different ways to change the project versions and set them to active with a script. Both scripts emulate the http requests which are sent to the read-the-docs server. I have a local running instance with http (without https) and it works, but I don´t know if it works for https too.
Maybe it is necessary to capture the packets via Wireshark and adapt the script.
First script (using Python):
def set_version_active_on_rtd():
server_addr = "http://192.168.1.100:8000"
project_slug = "myProject"
rtd_user = 'mylogin'
rtd_password = 'mypassword'
with requests.session() as s:
url = server_addr + "/accounts/login/"
# fetch the login page
s.get(url)
if 'csrftoken' in s.cookies:
# Django 1.6 and up
csrftoken = s.cookies['csrftoken']
else:
# older versions
csrftoken = s.cookies['csrf']
login_data = dict(login=rtd_user, password=rtd_password, csrfmiddlewaretoken=csrftoken, next='/')
r = s.post(url, data=login_data, headers=dict(Referer=url))
url = server_addr+"/dashboard/"+project_slug+"/versions/"
if 'csrftoken' in s.cookies:
# Django 1.6 and up
csrftoken = s.cookies['csrftoken']
else:
# older versions
csrftoken = s.cookies['csrf']
'''
These settings which are saved in version_data, are configured normally with help of the webinterface.
To set a version active, it must be configured with
'version-<version_number>':'on'
and its privacy must be set like
'privacy-<version_number>':'public'
To disable a version, its privacy has to be set and no other entry with 'on' has to be supplied
'''
version_data = {'default-version': 'latest', 'version-latest': 'on', 'privacy-latest' : 'public', 'privacy-master':'public','csrfmiddlewaretoken': csrftoken}
r = s.post(url, data = version_data, headers=dict(Referer=url))
Second script (bash and cUrl):
#!/bin/bash
RTD_SERVER='http://192.168.1.100:8000'
RTD_LOGIN='mylogin'
RTD_PASSWORD='mypassword'
RTD_SLUG='myProject'
#fetch login page and save first cookie
curl -c cookie1.txt "$RTD_SERVER"/accounts/login/ > /dev/null
#extract token from first cookie
TOKEN1=$(tail -n1 cookie1.txt | awk 'NF>1{print $NF}')
#login and send first cookie and save second cookie
curl -b cookie1.txt -c cookie2.txt -X POST -d
"csrfmiddlewaretoken=$TOKEN1&login=$RTD_LOGIN&\
password=$RTD_PASSWORD&next=/dashboard/"$RTD_SLUG"/versions/"
"$RTD_SERVER"/accounts/login/ > /dev/null
#extract token from second cookie
TOKEN2=$(tail -n3 cookie2.txt | awk 'NF>1{print $NF}' | head -n1)
# send data for the versions to the rtd server using the second cookie
curl -b cookie2.txt -X POST -d "csrfmiddlewaretoken=$TOKEN2&default-
version=latest&version-master=on&privacy-master=public&\
version-latest=on&privacy-latest=public"
$RTD_SERVER"/dashboard/"$RTD_SLUG"/versions/ > /dev/null
#delete the cookies
rm cookie1.txt cookie2.txt
To set a default-version, it can be necessary to run the script twice, if the version was not set to active. At the first run for activating the version, and at the second run to set it as default-version.
Hope it helps

Python: HTTP caching using 'CacheControl` not working

I'm using python 3.6 with requests module for API consumption and CacheControl module for caching the API response. I'm using following code but cache does not seems to be working:
import requests
from cachecontrol import CacheControl
sess = requests.session()
cached_sess = CacheControl(sess)
response = cached_sess.get('https://jsonplaceholder.typicode.com/users')
Every request to this URL returns the 200 status code (instead of 304 status code) and the same resource is requested each time even though the ETag headers is same and max-age was still valid. The API returns following cache related headers:
'Cache-Control': 'public, max-age=14400'
'Expires': 'Sat, 04 Feb 2017 22:23:28 GMT' (time of original request)
'Etag': 'W/"160d-MxiAGkI3ZBrjm0xiEDfwqw"'
What could be the issue here?
UPDATE: I'm not sending If-None-Match header with any API call, do I manually have to do it or CacheControl module should take care of it automatically?
Use a cache implementation to persist the cache between runs of the program.
from cachecontrol.caches import FileCache
sess = requests.session()
cached_sess = CacheControl(sess, cache = FileCache('.web_cache'))
Also, ensure you're using a recent CacheControl release. CacheControl has only cached resources served as Transfer-Encoding: chunked since 0.11.7:
$ curl -si https://jsonplaceholder.typicode.com/users | fgrep -i transfer-encoding
Transfer-Encoding: chunked
Every request to this URL returns the 200 status code
This is what you'll see when CacheControl is working correctly. The return of a cached response, or use of a 304, is hidden from you as a client of the code. If you believe that a fresh request is being made to the upstream server, consider something like:
import logging
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
to see what cachecontrol.controller and requests.packages.urllib3.connectionpool are doing.

Categories

Resources