Python-Jenkins tunnel connection failed: 403 Forbidden - python

I have been using the Python Jenkins APIs to manager my Jenkins jobs. It has worked for a long time, but it stopped suddenly working. This is the code excerpt:
import jenkins
server = jenkins.Jenkins('https://jenkins.company.com', username='xxxx', password='password')
server._session.verify = False
print(server.jobs_count())
The traceback:
File "", line 1, in
server.jobs_count()
File "E:\anaconda3\Lib\site-packages\jenkins_init_.py", line
1160, in jobs_count
return len(self.get_all_jobs())
File "E:\anaconda3\Lib\site-packages\jenkins_init_.py", line
1020, in get_all_jobs
jobs = [(0, [], self.get_info(query=jobs_query)['jobs'])]
File "E:\anaconda3\Lib\site-packages\jenkins_init_.py", line 769,
in get_info
requests.Request('GET', self._build_url(url))
File "E:\anaconda3\Lib\site-packages\jenkins_init_.py", line 557,
in jenkins_open
return self.jenkins_request(req, add_crumb, resolve_auth).text
File "E:\anaconda3\Lib\site-packages\jenkins_init_.py", line 573,
in jenkins_request
self.maybe_add_crumb(req)
File "E:\anaconda3\Lib\site-packages\jenkins_init_.py", line 371,
in maybe_add_crumb
'GET', self._build_url(CRUMB_URL)), add_crumb=False)
File "E:\anaconda3\Lib\site-packages\jenkins_init_.py", line 557,
in jenkins_open
return self.jenkins_request(req, add_crumb, resolve_auth).text
File "E:\anaconda3\Lib\site-packages\jenkins_init_.py", line 576,
in jenkins_request
self._request(req))
File "E:\anaconda3\Lib\site-packages\jenkins_init_.py", line 550,
in _request
return self._session.send(r, **_settings)
File "E:\anaconda3\Lib\site-packages\requests\sessions.py", line
622, in send
r = adapter.send(request, **kwargs)
File "E:\anaconda3\Lib\site-packages\requests\adapters.py", line
507, in send
raise ProxyError(e, request=request)
ProxyError: HTTPSConnectionPool(host='jenkins.company.com', port=443): Max
retries exceeded with url:
/job/scp/job/sm/job/9218/job/4198/job/SIT/crumbIssuer/api/json (Caused
by ProxyError('Cannot connect to proxy.', OSError('Tunnel connection
failed: 403 Forbidden')))
Note that there isn't any proxy on the Jenkins server, and I can use the user/password logon to the Jenkins server without any issues.
I have the crum id and API token, but I haven't found anything that is indicating how to add the crum into the Python-Jenkins API.

The final part of the traceback says:
ProxyError: HTTPSConnectionPool(host='ebs.usps.gov', port=443)
Which most likely indicates that you have proxy settings that your Python code inherits from somewhere when it runs. It could be environment variables ((HTTP|HTTPS)_PROXY) on POSIX sort of platforms or something similar... If you need to to use a proxy to reach the Jenkins instance, then the issue is in the proxy itself. It blocks your access for some reason. If you do not need to use a proxy, then you should remove the settings affecting your Python code when you run it.
Also, see what J_H said...

tl;dr: You lack connectivity.
The jenkins library depends on import requests,
which is reporting the connectivity error.
Regrettably, it uses ProxyError in the diagnostic.
The rationale goes like this:
We're making a GET request for the application.
Optionally the "GET from server S" will be turned into "GET from proxy P" if proxying is in use.
Eventually we try to contact some host, S or P. Might as well tell a proxy user that state of S is unknown, but state of P is "down".
Here ends the "why mention proxying?" diagnostic rant.
When you say "I'm not using proxying", I believe you.
The diagnostic can be a bit of a red herring for
folks who are not yet familiar with it.
When I probe ebs.usps.gov (56.207.107.97) on ports 443, 80, or with ICMP, I see zero response packets.
You're in a different part of the net, with different
filters between you and server, so your mileage might vary.
I wouldn't describe that host as a "public server",
since it offers me no responses.
It appears you sent SYN to tcp port 443,
and either some network device discarded that packet,
or the server replied with SYN-ACK and that
reply packet was discarded.
Most likely the server is down or your request was discarded.

Related

connect to docker hosted on remote server

How do I connect to remote docker host using python?
>>> from docker import Client
>>> cli = Client(base_url='tcp://52.90.216.176:2375')
>>>
>>> cli.containers()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/site-packages/docker/api/container.py", line 69, in containers
res = self._result(self._get(u, params=params), True)
File "/usr/local/lib/python2.7/site-packages/docker/utils/decorators.py", line 47, in inner
return f(self, *args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/docker/client.py", line 112, in _get
return self.get(url, **self._set_request_timeout(kwargs))
File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 480, in get
return self.request('GET', url, **kwargs)
File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 468, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 576, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python2.7/site-packages/requests/adapters.py", line 437, in send
raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='52.90.216.176', port=2375): Max retries exceeded with url: /v1.21/containers/json?all=0&limit=-1&trunc_cmd=0&size=0 (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7fd87d836750>: Failed to establish a new connection: [Errno 111] Connection refused',))
If I log-in to 52.90.216.176 and use the following:
>>> cli = Client(base_url='unix://var/run/docker.sock')
this works. But how do I connect to docker running on another server?
It sounds like you're using docker-py.
Also, it sounds like maybe you're not familiar with TLS, so please read the documentation for using TLS with docker-py. You may need to download your TLS files and copy them local to the docker-py client as they are used to authenticate that you are authorized to connect to the Docker daemon.
I hope your remote Docker daemon is not exposed to the world.
If it is not running TLS (exposed to the world):
client = docker.Client(base_url='<https_url>', tls=False)
If it is secured with TLS (not exposed to the world):
client = docker.Client(base_url='<https_url>', tls=True)
This is not answer, but need your feedback.
The error message is: Connection refused, so can you run the command:
telnet 52.90.216.176 2375
To confirm if there is no firewall issue. Sometime the port is 2376
Add tcp option to sys config as shown here:
vi /etc/sysconfig/docker
OPTIONS="--host=tcp://0.0.0.0:2375"
After restarting docker, I could connect to remote docker server using python.

Handling Non-SSL Traffic in Python/Tornado

I have a webservice running in python 2.7.10 / Tornado that uses SSL. This service throws an error when a non-SSL call comes through (http://...).
I don't want my service to be accessible when SSL is not used, but I'd like to handle it in a cleaner fashion.
Here is my main code that works great over SSL:
if __name__ == "__main__":
tornado.options.parse_command_line()
#does not work on 2.7.6
ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_ctx.load_cert_chain("...crt.pem","...key.pem")
ssl_ctx.load_verify_locations("...CA.crt.pem")
http_server = tornado.httpserver.HTTPServer(application, ssl_options=ssl_ctx, decompress_request=True)
http_server.listen(options.port)
mainloop = tornado.ioloop.IOLoop.instance()
print("Main Server started on port XXXX")
mainloop.start()
and here is the error when I hit that server with http://... instead of https://...:
[E 151027 20:45:57 http1connection:700] Uncaught exception
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/tornado/http1connection.py", line 691, in _server_request_loop
ret = yield conn.read_response(request_delegate)
File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 807, in run
value = future.result()
File "/usr/local/lib/python2.7/dist-packages/tornado/concurrent.py", line 209, in result
raise_exc_info(self._exc_info)
File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 810, in run
yielded = self.gen.throw(*sys.exc_info())
File "/usr/local/lib/python2.7/dist-packages/tornado/http1connection.py", line 166, in _read_message
quiet_exceptions=iostream.StreamClosedError)
File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 807, in run
value = future.result()
File "/usr/local/lib/python2.7/dist-packages/tornado/concurrent.py", line 209, in result
raise_exc_info(self._exc_info)
File "<string>", line 3, in raise_exc_info
SSLError: [SSL: HTTP_REQUEST] http request (_ssl.c:590)
Any ideas how I should handle that exception?
And what the standard-conform return value would be when I catch a non-SSL call to an SSL-only API?
UPDATE
This API runs on a specific port e.g. https://example.com:1234/. I want to inform a user who is trying to connect without SSL, e.g. http://example.com:1234/ that what they are doing is incorrect by returning an error message or status code. As it is the uncaught exception returns a 500, which they could interpret as a programming error on my part. Any ideas?
There's an excelent discussion in this Tornado issue about that, where Tornado maintainer says:
If you have both HTTP and HTTPS in the same tornado process, you must be running two separate HTTPServers (of course such a feature should not be tied to whether SSL is handled at the tornado level, since you could be terminating SSL in a proxy, but since your question stipulated that SSL was enabled in tornado let's focus on this case first). You could simply give the HTTP server a different Application, one that just does this redirect.
So, the best solution it's to HTTPServer that listens on port 80 and doesn't has the ssl_options parameter setted.
UPDATE
A request to https://example.com/some/path will go to port 443, where you must have an HTTPServer configured to handle https traffic; while a request to http://example.com/some/path will go to port 80, where you must have another instance of HTTPServer without ssl options, and this is where you must return the custom response code you want. That shouldn't raise any error.

check Python requests with charles proxy for HTTPS

I want to debug some python requests using charles proxy.
I need to include the certificate for charles on the call, but is not working
import requests
endpoint_url = 'https://www.httpsnow.org/'
r = requests.get(endpoint_url, verify=True, cert='/Users/iosdev/DopPy/charles.crt')
print "empexo"
print r
I have added the https address on Charles,
I get on Charles:
SSLHandshake: Remote host closed connection during handshake
and on python the log with error
empexo
Traceback (most recent call last):
File "/Users/iosdev/DopPy/GetCelebs.py", line 15, in <module>
r = requests.get(endpoint_url, verify=True, cert='/Users/iosdev/DopPy/charles.crt')
File "/Users/iosdev/VenvPY26/lib/python2.6/site-packages/requests/api.py", line 65, in get
return request('get', url, **kwargs)
File "/Users/iosdev/VenvPY26/lib/python2.6/site-packages/requests/api.py", line 49, in request
response = session.request(method=method, url=url, **kwargs)
File "/Users/iosdev/VenvPY26/lib/python2.6/site-packages/requests/sessions.py", line 461, in request
resp = self.send(prep, **send_kwargs)
File "/Users/iosdev/VenvPY26/lib/python2.6/site-packages/requests/sessions.py", line 573, in send
r = adapter.send(request, **kwargs)
File "/Users/iosdev/VenvPY26/lib/python2.6/site-packages/requests/adapters.py", line 431, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: [Errno 336265225] _ssl.c:341: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib
Process finished with exit code 1
I found this thread while I was troubleshooting a similar issue. In the scenario I ran into the cert argument was being used to define the path to a ".crt" file when the verify argument should have been used instead.
The correct usage ended up looking like:
requests.get(endpoint_url, verify='/path/to/file.crt')
See Requests' documentation for more details: https://2.python-requests.org/en/v1.1.0/user/advanced/#ssl-cert-verification
As an aside, I find employing Request's ability to specify the path to a ".crt" via the REQUESTS_CA_BUNDLE environmental variable more effective when using Charles Proxy for local debugging.
Running something like the following in shell saves having to specify the path to Charles' ".crt" for every Requests call:
REQUESTS_CA_BUNDLE=/path/to/file.crt
export REQUESTS_CA_BUNDLE

Name or service not known error in EasyWebDav for Python

I'm trying to setup a WebDAV connection using easywebdav in Python. (Using 2.7.8 for now)
import csv, easywebdav
webdav=easywebdav.connect('https://sakai.rutgers.edu/dav/restoftheurl,username="",password="")
print webdav.ls()
Though when I run this I get the following error message. My guess is that it possibly has something to do with the URL using HTTPS?
Traceback (most recent call last):
File "/home/willkara/Development/SakaiStuff/WorkProjects/sakai-manager/file.py", line 4, in <module>
print webdav.ls()
File "build/bdist.linux-x86_64/egg/easywebdav/client.py", line 176, in ls
File "build/bdist.linux-x86_64/egg/easywebdav/client.py", line 97, in _send
File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 456, in request
resp = self.send(prep, **send_kwargs)
File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 559, in send
r = adapter.send(request, **kwargs)
File "/usr/lib/python2.7/dist-packages/requests/adapters.py", line 375, in send
raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='https', port=80): Max retries exceeded with url: //sakai.rutgers.edu/dav/url:80/. (Caused by <class 'socket.gaierror'>: [Errno -2] Name or service not known)
[Finished in 0.1s with exit code 1]
I find it strange that you combine HTTPS protocol and port 80. HTTPS uses port 443.
Though the error message "Name or service not known" would rather indicate that the hostname sakai.rutgers.edu is not recognized on your system. Try to ping the host.
I noticed that you shouldn't have http:// or https:// in the beginning of your adress, only the host name. You select protocol with protocol='https'. Also, I couln't get it to work if I added the path the url, I had to use it as argument to the operations like easywebdav.ls('/dav/restoftheurl') or easywebdav.cd('/dav/restoftheurl').

AppEngine: gaierror when starting a task

I ran into an error that was painful to track down, so I thought I'd add the cause + "solution" here.
The setup:
Devbox - Running Google App Engine listening on all ports ("--address=0.0.0.0") serving a URL that launches a task.
Client - Client (Python requests library) which queries the callback URL
App Engine code:
class StartTaskCallback(webapp.RequestHandler):
def post(self):
param = self.request.get('param')
logging.info('STARTTASK: %s' % param)
# launch a task
taskqueue.add(url='/tasks/mytask',
queue_name='myqueue',
params={'param': param})
class MyTask(webapp.RequestHandler):
def post(self):
param = self.request.get('param')
logging.info('MYTASK: param = %s' % param)
When I queried the callback with my browser, everything worked, but the same query from the remote client gave me the following error:
ERROR 2012-03-23 21:18:27,351 taskqueue_stub.py:1858] An error occured while sending the task "task1" (Url: "/tasks/mytask") in queue "myqueue". Treating as a task error.
Traceback (most recent call last):
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/taskqueue/taskqueue_stub.py", line 1846, in ExecuteTask
connection.endheaders()
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 868, in endheaders
self._send_output()
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 740, in _send_output
self.send(msg)
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 699, in send
self.connect()
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 683, in connect
self.timeout)
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/socket.py", line 498, in create_connection
for res in getaddrinfo(host, port, 0, SOCK_STREAM):
gaierror: [Errno 8] nodename nor servname provided, or not known
This error would just spin in a loop as the task retried. Though oddly, I could go to Admin -> Task Queues and click 'Run' to get the task to complete successfully.
At first I thought this was an error with the binding. I would not get an error if I queried the StartTaskCallback via the browser or if I ran the client locally.
Finally I noticed that App Engine is using the 'host' field of the request in order to build an absolute URL for the task. In /Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/taskqueue/taskqueue_stub.py (1829):
connection_host, = header_dict.get('host', [self._default_host])
if connection_host is None:
logging.error('Could not determine where to send the task "%s" '
'(Url: "%s") in queue "%s". Treating as an error.',
task.task_name(), task.url(), queue.queue_name)
return False
connection = httplib.HTTPConnection(connection_host)
In my case, I was using a special name + hosts file on the remote client to access the server.
192.168.1.208 devbox
So the 'host' for the remote client looked like 'devbox:8085' which the local server could not resolve.
To fix the issue, I simply added devbox to my AppEngine server's hosts file, but it sure would have been nice if the gaierror exception had printed the name it failed to resolve, or if App Engine didn't use the 'host' of the incoming request to build a URL for task creation.

Categories