Update URLS that require depth or tree filters

Some API endpoints require the use of a filter or they will respond
with HTTP error code 418 I'm a teapot.

This was seen on CloudBees Jenkins Enterprise 2.107.2.1-rolling.

Adding a depth filter will ensure the API calls will succeed.

Change-Id: Ib4d6a251bf3a024a76081b2fc83baa7839ad4015
This commit is contained in:
JP Sullivan 2018-05-25 17:49:47 +01:00
parent cd440ab4ac
commit f1f97ab4bf
5 changed files with 52 additions and 13 deletions

View File

@ -95,13 +95,13 @@ DEFAULT_HEADERS = {'Content-Type': 'text/xml; charset=utf-8'}
INFO = 'api/json' INFO = 'api/json'
PLUGIN_INFO = 'pluginManager/api/json?depth=%(depth)s' PLUGIN_INFO = 'pluginManager/api/json?depth=%(depth)s'
CRUMB_URL = 'crumbIssuer/api/json' CRUMB_URL = 'crumbIssuer/api/json'
WHOAMI_URL = 'me/api/json' WHOAMI_URL = 'me/api/json?depth=%(depth)s'
JOBS_QUERY = '?tree=jobs[url,color,name,jobs]' JOBS_QUERY = '?tree=jobs[url,color,name,jobs]'
JOB_INFO = '%(folder_url)sjob/%(short_name)s/api/json?depth=%(depth)s' JOB_INFO = '%(folder_url)sjob/%(short_name)s/api/json?depth=%(depth)s'
JOB_NAME = '%(folder_url)sjob/%(short_name)s/api/json?tree=name' JOB_NAME = '%(folder_url)sjob/%(short_name)s/api/json?tree=name'
ALL_BUILDS = '%(folder_url)sjob/%(short_name)s/api/json?tree=allBuilds[number,url]' ALL_BUILDS = '%(folder_url)sjob/%(short_name)s/api/json?tree=allBuilds[number,url]'
Q_INFO = 'queue/api/json?depth=0' Q_INFO = 'queue/api/json?depth=0'
Q_ITEM = 'queue/item/%(number)d/api/json' Q_ITEM = 'queue/item/%(number)d/api/json?depth=%(depth)s'
CANCEL_QUEUE = 'queue/cancelItem?id=%(id)s' CANCEL_QUEUE = 'queue/cancelItem?id=%(id)s'
CREATE_JOB = '%(folder_url)screateItem?name=%(short_name)s' # also post config.xml CREATE_JOB = '%(folder_url)screateItem?name=%(short_name)s' # also post config.xml
CONFIG_JOB = '%(folder_url)sjob/%(short_name)s/config.xml' CONFIG_JOB = '%(folder_url)sjob/%(short_name)s/config.xml'
@ -122,7 +122,7 @@ BUILD_TEST_REPORT = '%(folder_url)sjob/%(short_name)s/%(number)d/testReport/api/
'?depth=%(depth)s' '?depth=%(depth)s'
DELETE_BUILD = '%(folder_url)sjob/%(short_name)s/%(number)s/doDelete' DELETE_BUILD = '%(folder_url)sjob/%(short_name)s/%(number)s/doDelete'
WIPEOUT_JOB_WORKSPACE = '%(folder_url)sjob/%(short_name)s/doWipeOutWorkspace' WIPEOUT_JOB_WORKSPACE = '%(folder_url)sjob/%(short_name)s/doWipeOutWorkspace'
NODE_LIST = 'computer/api/json' NODE_LIST = 'computer/api/json?depth=%(depth)s'
CREATE_NODE = 'computer/doCreateItem' CREATE_NODE = 'computer/doCreateItem'
DELETE_NODE = 'computer/%(name)s/doDelete' DELETE_NODE = 'computer/%(name)s/doDelete'
NODE_INFO = 'computer/%(name)s/api/json?depth=%(depth)s' NODE_INFO = 'computer/%(name)s/api/json?depth=%(depth)s'
@ -578,7 +578,7 @@ class Jenkins(object):
raise TimeoutException('Error in request: %s' % (e.reason)) raise TimeoutException('Error in request: %s' % (e.reason))
raise JenkinsException('Error in request: %s' % (e.reason)) raise JenkinsException('Error in request: %s' % (e.reason))
def get_queue_item(self, number): def get_queue_item(self, number, depth=0):
'''Get information about a queued item (to-be-created job). '''Get information about a queued item (to-be-created job).
The returned dict will have a "why" key if the queued item is still The returned dict will have a "why" key if the queued item is still
@ -755,7 +755,7 @@ class Jenkins(object):
raise JenkinsException("Could not parse JSON info for server[%s]" raise JenkinsException("Could not parse JSON info for server[%s]"
% self.server) % self.server)
def get_whoami(self): def get_whoami(self, depth=0):
"""Get information about the user account that authenticated to """Get information about the user account that authenticated to
Jenkins. This is a simple way to verify that your credentials are Jenkins. This is a simple way to verify that your credentials are
correct. correct.
@ -771,7 +771,7 @@ class Jenkins(object):
""" """
try: try:
response = self.jenkins_open(requests.Request( response = self.jenkins_open(requests.Request(
'GET', self._build_url(WHOAMI_URL) 'GET', self._build_url(WHOAMI_URL, locals())
)) ))
if response is None: if response is None:
raise EmptyResponseException( raise EmptyResponseException(
@ -1410,7 +1410,7 @@ class Jenkins(object):
'executor': executor_number}) 'executor': executor_number})
return builds return builds
def get_nodes(self): def get_nodes(self, depth=0):
'''Get a list of nodes connected to the Master '''Get a list of nodes connected to the Master
Each node is a dict with keys 'name' and 'offline' Each node is a dict with keys 'name' and 'offline'
@ -1419,7 +1419,7 @@ class Jenkins(object):
''' '''
try: try:
nodes_data = json.loads(self.jenkins_open( nodes_data = json.loads(self.jenkins_open(
requests.Request('GET', self._build_url(NODE_LIST)))) requests.Request('GET', self._build_url(NODE_LIST, locals()))))
return [{'name': c["displayName"], 'offline': c["offline"]} return [{'name': c["displayName"], 'offline': c["offline"]}
for c in nodes_data["computer"]] for c in nodes_data["computer"]]
except (req_exc.HTTPError, BadStatusLine): except (req_exc.HTTPError, BadStatusLine):

View File

@ -45,7 +45,7 @@ class JenkinsGetNodesTest(JenkinsNodesTestBase):
self.j.get_nodes() self.j.get_nodes()
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].url, jenkins_mock.call_args[0][0].url,
self.make_url('computer/api/json')) self.make_url('computer/api/json?depth=0'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Could not parse JSON info for server[{0}]'.format( 'Could not parse JSON info for server[{0}]'.format(
@ -74,7 +74,7 @@ class JenkinsGetNodesTest(JenkinsNodesTestBase):
self.j.get_nodes() self.j.get_nodes()
self.assertEqual( self.assertEqual(
session_send_mock.call_args_list[1][0][1].url, session_send_mock.call_args_list[1][0][1].url,
self.make_url('computer/api/json')) self.make_url('computer/api/json?depth=0'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Error communicating with server[{0}]'.format( 'Error communicating with server[{0}]'.format(

View File

@ -107,5 +107,5 @@ class JenkinsQueueItemTest(JenkinsTestBase):
self.assertEqual(queue_item, queue_item_to_return) self.assertEqual(queue_item, queue_item_to_return)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].url, jenkins_mock.call_args[0][0].url,
self.make_url('queue/item/25/api/json')) self.make_url('queue/item/25/api/json?depth=0'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -0,0 +1,39 @@
import jenkins
from tests.base import JenkinsTestBase
# Vars in the jenkins module scope that do not need validating
VAR_WHITELIST = ['__doc__',
'__file__',
'__name__',
'__package__',
'CRUMB_URL',
'DEFAULT_HEADERS',
'EMPTY_CONFIG_XML',
'EMPTY_FOLDER_XML',
'EMPTY_PROMO_CONFIG_XML',
'EMPTY_VIEW_CONFIG_XML',
'INFO',
'LAUNCHER_SSH',
'LAUNCHER_COMMAND',
'LAUNCHER_JNLP',
'LAUNCHER_WINDOWS_SERVICE',
'NODE_TYPE',
'PROMO_RECONFIG_XML',
'RECONFIG_XML']
class JenkinsRestTest(JenkinsTestBase):
# If there is no filter (depth or tree) we will get an exception
# on some Jenkins instances
def test_url_has_filter(self):
for var in dir(jenkins):
if var in VAR_WHITELIST:
continue
# Misses unicode on 2.x
val = getattr(jenkins, var)
if isinstance(val, str):
# If we end the path in api/json and don't have depth or tree encoded, fail
self.assertEqual(val.endswith('api/json'), False,
"URLS that end in 'api/json' must be called with depth or tree:" +
"var: [{}] val: [{}]".format(var, val))

View File

@ -31,7 +31,7 @@ class JenkinsWhoamiTest(JenkinsTestBase):
self.assertEqual(user, user_to_return) self.assertEqual(user, user_to_return)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].url, jenkins_mock.call_args[0][0].url,
self.make_url('me/api/json')) self.make_url('me/api/json?depth=0'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@patch('jenkins.requests.Session.send', autospec=True) @patch('jenkins.requests.Session.send', autospec=True)
@ -45,4 +45,4 @@ class JenkinsWhoamiTest(JenkinsTestBase):
self.j.get_whoami() self.j.get_whoami()
self.assertEqual( self.assertEqual(
session_send_mock.call_args_list[1][0][1].url, session_send_mock.call_args_list[1][0][1].url,
self.make_url('me/api/json')) self.make_url('me/api/json?depth=0'))