We handle 401, 403, 500 and 404 everything else currently returns None
breaking parsing in the callers with hard to track down errors.
Just raise the actual HTTP error in that case.
Change-Id: I35e4f082069941cd5a8d97185693501ab2b0dc6f
If jenkins_open fails with an empty response we don't set a crumb. The
rest of the code will figure out the real error later.
Change-Id: Ib1743101b6a474656909fc1cb7989c971a56f187
Without a timeout a script can hang forever when attempting
to connect to jenkins. This change sets a default timeout
of 2 minutes. Selection of default value is pretty arbitrary
on this change.
Closes-Bug: #1273329
Change-Id: If84778231b88d78a02a89a56f38f95d6deada80a
Now that the jenkins_open() method will raise a specific exception
if Jenkins returns a 404, some calls to assert_job_exists() now
become redundant. Since these calls represent an extra round-trip
with the Jenkins server, dropping them will result in a reduction
in time taken for such things as a jenkins-job run. This change
eliminates the redundant calls and adjusts the tests as appropriate.
Change-Id: If78dea9ad60d446854d24919bdd7f3f1fee3d733
Currently, when Jenkins returns a 404 error, the jenkins_open()
method gives no indication. This adds a new NotFoundException,
descending from JenkinsException, which can be used to distinguish
this case. This causes a problem with cancel_queue(), however,
as the Jenkins API always returns a 404; since cancel_queue() is
a best-effort mechanism, this change also modifies that method to
explicitly ignore a NotFoundException. The maybe_add_crumb()
method also has to be updated to properly handle 404s, for the
case where crumbs are disabled. The get_job_name() method is also
adjusted to return None if jenkins_open() raises a NotFoundException.
A few quick google searches shows that only the cancelItem
endpoint will always return 404.
Change-Id: I98320d174659fc83d48614b31a5a054fd0773dfe
Closes-Bug: #1246468
The cancel_queue() method needed updating because the jenkins URL
for it has changed and the request requires a POST to work.
Closes-Bug: #1246466
Change-Id: I89fcee3715c67a989a08ca75c0232c4fd87375c0
The disable_node() and enable_node() requires a POST otherwise it doesn't
do anything. This change modifies the request to a POST.
Change-Id: Id320d42908cc695c38a72d1a09d9cf022bbbea80
The current methods do not work for jobs and node that contain spaces in
their names. This change adds quotes around the names in the jenkins
URL so that Jenkins will be able to process the URL correctly.
Closes-Bug: #1000799
Closes-Bug: #1183958
Change-Id: I86ac5aa8b2ff9b92ba240637f4a225978236e6db
Having only the error code from urllib is not that interesting.
HTTPError inherits from URLError which has a 'msg' attribute. Output it
along the error code.
HTTPError does not have a 'reason' attribute although python six
provides it for py27 and later. So fallback to 'msg'.
Change-Id: I591684785fd7af43b833e84fa1e40f46a852bef2
Our auth_headers() helper uses base64.encodestring() which inserts
newlines to generate a nicely formatted text. That is surely helpful for
display purposes but unwanted when forging an authentication string.
encodestring() always append a newline, which was the reason for the
[:-1] slicing.
Switch to base64.b64encoding() and add a test ensuring no newline is
inserted.
Closes-Bug: 1039307
Change-Id: I71c3e6d504a500a1f21ff89b1d54a155da1aaf0e
This change adds methods to retrieve jenkins plugin information.
get_plugins_info - will return a list containing all installed plugins.
get_plugin_info - will query (by name) for a specific plugin and return
info on that plugin.
Change-Id: Ia6cd90571ff260aec9869f48df06486b7fac181f
Add a method to get the Jenkins server (or master) version
Signed-off-by: Antoine Musso <hashar@free.fr>
Change-Id: I9bbcf5fd1615246e53a9d83fec9d0c93c64b15aa
Bring support for node configuration with get_node_config() and
reconfig_node(). This comes from OpenStack Nodepool project originally
written by James E. Blair in the devstack-gate project.
Closes-Bug: #1234273
Change-Id: I29423d8bab5fd74f1c7f63002d1be7a2ae0be176
The build_job method would not trigger a build because it
would do a GET on the build URL rather than a POST. Adding
a body causes it to do a POST.
Change-Id: Idf40e462f970122234f85b5d1d2e72d178b5b39f
Closes-Bug: 1177831
This is similar to recently introduced assert_job_exists(). It will
throws an exception whenever a node is missing and further customize the
exception messages.
Replace an occurence of:
if not self.node_exists(name):
raise JenkinsException('node[%s] already exists' % (name))
By:
self.assert_node_exists(name, 'node[%s] already exists')
Change-Id: Ia2e91843b353c02fb19290eadbbb83db8d2a3124
Most methods are asserting that a job exists by calling get_job_info().
Unfortunately that might trigger on the server side a parse of the full
job history to gather the lastSuccessful, lastFailure build numbers.
Since Jenkins is heavily file based, the process is rather long on jobs
having thousands and thousands of build.
Since we only care about checking whether the job exists, introduce
job_exists() which is light on the server side. To throw exception,
this also introduce the wrapper assert_job_exists() which can futher
customize the exception messages.
Updates all constructs such as:
if not self.job_exists(job_name):
raise JenkinsException(<some message> % (job_name))
To:
self.assert_job_exists(to_name, <some message>)
That speed up operations tremendously whenever the targetted jobs are
very long.
Added coverage test.
Change-Id: I946dbb7a08a8bb172a369af3b2aedc07e3cea9e6
To verify a job exist, we query Jenkins API and attempt to load the
resulting JSON. The error message is very simple:
Jenkins returned an unexpected job name
This patch add the actual job name received and the expected one. That
might help diagnosis.
Change-Id: Ib13c3bb8d265612811714d10818364956f84a341
Use tox configuration to expose linting and unit testing. Will let us
integrate them with OpenStack continuous integration infrastructure.
* updates .gitignore following the migration from bzr
* get rid of the old Makefile in favor of tox
* remove .pep8 file (that is now a [flake8] section in tox.ini)
* fix a few trivial pep8 errors (comments must start with '# ' and
modulo operator needs surrounding spaces) but ignore 'line too long
(E501)' for now.
* write module requirements in /test-requirements.txt. Discover is
needed for python 2.6.
* change the test command that cames from the Makefile so it works with
python 2.6
Change-Id: If58730d84315c0ea018a3757624d98bf2e1aeb3f
The job_exists() methods rely on an API call that cause Jenkins to LazyLoad the
build history. Whenever a job has a huge build history, that would be awfully
slow. The API let you fetch only a subset of the information you need by using
the 'tree' parameter, by requesting only the name of the job, we ensure the
server is only going to do a very simple operation.
It is then only a matter of checking the job name returned the API is equal to
the one requested, that validates the job exists and is accessible.
Tested out on a dev setup with a job having a million builds:
import jenkins
from pprint import pprint
j = jenkins.Jenkins('https://localhost:8080/')
for job_name in ['huge-history', 'Idonotexist']:
print "Getting job name of %s" % job_name
pprint(j.get_job_name(job_name))
print "Does it exist?"
pprint(j.job_exists(job_name))
Output:
Getting job name of huge-history
u'huge-history'
Does it exist?
True
Getting job name of Idonotexist
None
Does it exist?
None
Sphinx:
* Build dir is now named `build` and the files are under `source`.
* MakeFile learned texinfo, info and gettext targets
* include __init__ documentation (autoclass_content)
* keep file ordering for methods (autodoc_member_order)
* comment out html_static_path to get rid of a warning
Doc:
* Index is now... an index! Takes advantage of :glob: to automatically
create a complete table of content.
* Creates API reference which list the documentation directly from the
jenkins/__init__.py file. That will avoid the documentation duplication
and some out of sync documentation.
* insert the module in the path to document it
* the example were both in index.rst and __init__.py create a new section
with example.rst. That can be later be improved with some typical use
cases.
* A couple documentation update to some methods. The inline documentation
was out of sync though the index.rst got updated.