joelee2012 / api4jenkins Goto Github PK
View Code? Open in Web Editor NEWPython sync/async client library for Jenkins API
Home Page: https://api4jenkins.readthedocs.io/
License: Apache License 2.0
Python sync/async client library for Jenkins API
Home Page: https://api4jenkins.readthedocs.io/
License: Apache License 2.0
Thanks for the wrapper.
Apologies if I have missed it, but is there a way to retrieve all builds of a job?
E.g. I have a job that has about 1000 builds, but when I run for build in job:
it only gets the most recent 100.
In the Jenkins api reference it says you have to use the tree=allBuilds[…]
parameter to force it to load all of the builds.
Thanks.
When using a non-default port, e.g.
J = Jenkins('http://localhost:9090/', auth=('admin', 'admin'))
job = J.get_job('MetaWorker')
item = job.build()
the library still uses port 8080.
requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /job/MetaWorker/build (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fae50594e20>: Failed to establish a new connection: [Errno 61] Connection refused'))
Hello,
please, could you help me with my little issue? I'm trying to trigger build with one parameter.
'defaultParameterValue': {'_class': 'hudson.model.BooleanmParameterValue', 'name': 'UT', 'value': False}
I have tried:
.build(params=True)
.build(params=[True])
.build(params={'UT': True})
.build(params=[{'name': 'UT', 'value': True])
I wonder, should I completely copy job.get_parameters() and somehow change the value? Thank you.
Hi Support,
i got error from smoke-test_1 | File "/usr/local/lib/python3.10/site-packages/api4jenkins/job.py", line 159, in get_build smoke-test_1 | if int(number) == int(item['number']): smoke-test_1 | ValueError: invalid literal for int() with base 10: '1521-sit02-master'
Because our build number included string. Have anything possible to fix?
File "/usr/local/lib/python3.10/site-packages/api4jenkins/job.py", line 159, in get_build smoke-test_1 | if int(number) == int(item['number']):
remove int transition? thanks
[ok, not really an issue, could be more of a question ; not sure there is a forum for questions - I tried StackOverflow, where I saw a tag for api4jenkins
]
I am trying to build stats on Jenkins jobs. I need to access a few of the job properties, like the URL of the git repo used, as seen in the UI ( here, in Source Code Management \ Git \ Repositories \ Repository URL )
However, I do not understand how to get that property , I am actually getting a small subset of the properties I see in the UI. ( my jobs are all FreeStyleProject )
from api4jenkins import Jenkins
client = Jenkins(JENKINS_BASE_URL, auth=(USERNAME, PASSWORD))
api_jobs = client.get_job('a_folder')
for j in api_jobs :
print(j.name) # FreeStyleProject, by the way
pprint.pprint(j.api_json())
pprint.pprint(j.configure())
-> no SCM, Git or Bitbucket properties in the returned data
Hi there,
thanks for useful framework!
Intro
I've a nginx proxy with internal httpotp auth for jenkins auth.
For api4jenkins scripts I've used an internal server url, like http://jenkins:8080/
to skip httpauth for local scripts.
For user auth, I'm using an external server url, like https://jenkins-in-house.com/
The issue.
For some cases, api4jenkins returns server url described in Manage Jenkins - Configure System - Jenkins Location - Jenkins URL
instead of initialized object url
j = Jenkins('http://the_jenkins:8080/', auth=('automation', 'token'))
print(j)
print(j.url)
for job in j.iter_jobs():
print(f"job = {job}")
print(f"name = {name}")
......
<Jenkins: http://the_jenkins:8080/>
http://the_jenkins:8080/
job = <WorkflowJob: https://jenkins-in-house.com/job/Just_some_job/>
name = Just_some_job
Is is possible to use server url that initialized for auth, instead of jenkins url?
Thanks!
as the title said
my test code
client = JenkinsApi(self.url, auth=(self.user, self.token))
job = client.get_job(full_name)
print(f"====> debug job: {job} ")
build = job.get_build(number)
# build = j.get_last_build() # this is ok
print(f"====> debug build: {build} ")
Traceback (most recent call last):
File "jenkins_handler.py", line 52, in set_plugin_update_server
self._jenkins.plugins.set_site(update_server)
File "/usr/local/python375/lib/python3.7/site-packages/api4jenkins/plugin.py", line 38, in set_site
self.check_update_server()
File "/usr/local/python375/lib/python3.7/site-packages/api4jenkins/item.py", line 128, in getattr
return super().getattribute(name)
AttributeError: 'PluginsManager' object has no attribute 'check_update_server'
plugin.py", line 38, in set_site
self.check_update_server() -> self.check_updates_server()
Great library! It would be great to enable the use of existing api tokens so usernames / passwords aren't passed around in plaintext. Something like:
j = Jenkins(url, api_token="xyz")
Would preserve backwards compatibility
Hi when I call item.get_build() after having started a job the get_build() goes in error.
The stack trace is:
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/api4jenkins/item.py", line 73, in handle_req
return self.jenkins.send_req(method, self.url + entry, **kwargs)
File "/usr/local/lib/python3.6/site-packages/api4jenkins/requester.py", line 28, in send
resp.raise_for_status()
File "/usr/local/lib/python3.6/site-packages/requests/models.py", line 960, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 404 Client Error: Not Found for url: https://myjenkins.mycompany.com/job/APP1/job/APP1_BLABLA/job/APP1_BLABLA_BLABLA/12/api/json?depth=0&tree=queueId
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/var/lib/jenkins/workspace/Test/Git/myJclient/scripts/job1.py", line 22, in main
while not item.get_build():
File "/usr/local/lib/python3.6/site-packages/api4jenkins/queue.py", line 62, in get_build
if int(build.queue_id) == self.id:
File "/usr/local/lib/python3.6/site-packages/api4jenkins/item.py", line 129, in __getattr__
return self.api_json(tree=attr)[attr]
File "/usr/local/lib/python3.6/site-packages/api4jenkins/item.py", line 68, in api_json
return self.handle_req('GET', 'api/json', params=params).json()
File "/usr/local/lib/python3.6/site-packages/api4jenkins/item.py", line 77, in handle_req
f'Not found {entry} for item: {self}') from e
api4jenkins.exceptions.ItemNotFoundError: Not found api/json for item: <WorkflowRun: https://myjenkins.mycompany.com/job/APP1/job/APP1_BLABLA/job/APP1_BLABLA_BLABLA/12/>
I understood the error, on my jenkins (multinode) some user aborted a job but jenkins did not delete it from the queue (zombie job in the queue) and the get_build() goes in error.
This is my code:
# Create Jenkins client
j = Jenkins('https://'+baseurl, auth=(username, password), verify=False)
# Run build with args
item = j.build_job(jobname,
param1=param1_value,
param2=param2_value,
param3=param3_value
)
# Wait for the queue element
while not item.get_build():
time.sleep(1)
I know that only the first 100 builds are obtained now, but get_build(number) should be free to specify the build number to be reasonable
def get_build(self, number):
for item in self.api_json(tree='allBuilds[number,displayName,url]')['allBuilds']:
if number == item['number'] or number == item['displayName']:
return self._new_instance_by_item('api4jenkins.build', item)
return None
So it should be fine to change it to the above, except that it may be slower
api4jenkins/api4jenkins/job.py
Lines 59 to 61 in 4571292
def create(self, name, xml):
return self.handle_req('POST', 'createItem', params={'name': name},
headers=self.headers, data=xml.encode('utf-8'))
My code is:
from api4jenkins import Jenkins as aj
def api4jenkins_test(jenkins_url, username, password, job_name):
client = aj(jenkins_url, auth=(username, password))
item = client.build_job(job_name)
while not item.get_build():
time.sleep(1)
build = item.get_build()
for line in build.progressive_output():
print(line)
Jenkins Version: Jenkins 2.346.1
Traceback (most recent call last):
File "/home/njagadeesh/workspace/testjob/run_jenkins_api.py", line 52, in
api4jenkins_test(jenkins_url, username, password, job_name)
File "/home/njagadeesh/workspace/testjob/run_jenkins_api.py", line 35, in api4jenkins_test
item = client.build_job(job_name)
File "/home/njagadeesh/ve3/lib/python3.10/site-packages/api4jenkins/init.py", line 185, in build_job
job = self._get_job_and_check(full_name)
File "/home/njagadeesh/ve3/lib/python3.10/site-packages/api4jenkins/init.py", line 189, in _get_job_and_check
job = self.get_job(full_name)
File "/home/njagadeesh/ve3/lib/python3.10/site-packages/api4jenkins/init.py", line 74, in get_job
if folder.exists():
File "/home/njagadeesh/ve3/lib/python3.10/site-packages/api4jenkins/item.py", line 111, in exists
self.api_json(tree='_class')
File "/home/njagadeesh/ve3/lib/python3.10/site-packages/api4jenkins/item.py", line 97, in api_json
return self.handle_req('GET', 'api/json', params=params).json()
File "/home/njagadeesh/ve3/lib/python3.10/site-packages/api4jenkins/item.py", line 100, in handle_req
self._add_crumb(self.jenkins.crumb, kwargs)
File "/home/njagadeesh/ve3/lib/python3.10/site-packages/api4jenkins/init.py", line 248, in crumb
'GET', f'{self.url}crumbIssuer/api/json').json()
File "/home/njagadeesh/ve3/lib/python3.10/site-packages/httpx/_models.py", line 764, in json
return jsonlib.loads(self.content, **kwargs)
File "/usr/lib/python3.10/json/init.py", line 346, in loads
return _default_decoder.decode(s)
File "/usr/lib/python3.10/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib/python3.10/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Not sure if this is older jenkins version
File "./web/api/application/service.py", line 243, in _process_production_flow
while not item.get_build():
File "/usr/local/lib/python3.8/site-packages/api4jenkins/queue.py", line 58, in get_build
for build in self.jenkins.nodes.iter_builds():
File "/usr/local/lib/python3.8/site-packages/api4jenkins/node.py", line 48, in iter_builds
yield self._new_instance_by_item('api4jenkins.build',
File "/usr/local/lib/python3.8/site-packages/api4jenkins/item.py", line 96, in _new_instance_by_item
class_name = self.class_delimiter.split(item['_class'])[-1]
TypeError: 'NoneType' object is not **subscriptable**
hi, thanks for your good quality python jenkins client :)
i got error when waiting build items
The recursive
is added in create_job
in #48. So other related functions need to add it, too:
update
api4jenkins/api4jenkins/__init__.py
Line 126 in 4571292
self.create_job(folder.full_name, EMPTY_FOLDER_XML, recursive=recursive)
and update
api4jenkins/api4jenkins/job.py
Lines 34 to 35 in 4571292
def duplicate(self, path, recursive=False):
self.jenkins.create_job(path, self.configure(), recursive=recursive)
I want to change many nodes' labels by API, but I couldn't find which one to use.
The following code returns None
:
j.get_job('non-existed-job')
The following code raises an ItemNotFoundError
exception:
j.get_job('non-existed-folder/non-existed-job')
ver:1.9
This could help with autocompletion in editors.
Current:
Here I (/editor) do not know what the return type of get_job would be
client = Jenkins('jen_url', auth=('user', 'pass'))
project: WorkflowMultiBranchProject = client.get_job(full_name="project")
job: WorkflowJob = project.get(name="branch")
job.build()
After adding types:
client = Jenkins('jen_url', auth=('user', 'pass'))
project= client.get_job(full_name="project")
job = project.get(name="branch")
job.build()
Version 2.0.0 includes changes that use the walrus operator (:=
), but setup.py still has python_requires='>=3.7'
. Since the walrus operator was introduced in Python 3.8, this causes syntax errors upon import.
>>> import api4jenkins
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/jovyan/conda-envs/py37/lib/python3.7/site-packages/api4jenkins/__init__.py", line 160
if job := self.get_job(full_name):
^
SyntaxError: invalid syntax
folderJob.description
& folderJob.set_description()
get and set the All view
's description instead of the job folder description.
If we have multiple views, the other views aren't touched.
If there is an API to dump build parameters to JSON/YAML file, will help a lot for next time build job.
Thanks!
Currently if fails on _new_instance_by_item()
since the _class
is `jenkins.branch.OrganizationFolder``
From branch-api-plugin
https://github.com/jenkinsci/branch-api-plugin/blob/master/src/main/java/jenkins/branch/OrganizationFolder.java
Any workarounds are welcome.
Hi!
Not a real issue, but I stumbled over the build_job method, which simply do a
return handle_req('POST', entry, params=params)
Well, "params=params" is quite static, after some digging you always using "**kwargs" down to the Requester-method.
I personally didnt get a build with that method to work, so I had to modify it to
return handle_req('POST', entry, **kwargs)
the strict "params=params" makes no sence to me.
cheers
Matt
Feature request:
We use pools of nodes, and operate on subsets.
eg "FOO_1", "FOO_2", "BAR"
jenkins:8080/labels/FOO_1&&FOO_2||BAR
In groovy, we use
// get a list of nodes, excluding those which are offline (removes 'master')
def nlist = nodesByLabel(label: "${poollist}", offline: `false).sort()
Could you add something similar ?
Thanks
Hi
Currently the job.py/Project.build is only accepting parameters, this doesn't include any file parameter. Even if we pass a file parameter, this won't be properly mapped to requests
file parameter. So, either we need to separate the file
from params
and pass it to self.handle_req
method in build
method. But this may create a conflict if the job already has a parameter named file
. The following method does the job, but duplicates part of job.py/Project.build
def build_job_with_files(self, files: dict, **params) -> QueueItem:
"""
same function from api4jenkins.job.Project.build. Added files additionally.
:param files: dict of all file inputs with field name and file object like {'jsonfile': <fp>}
:param params: build params
"""
reserved = ['token', 'delay']
if not params or all(k in reserved for k in params):
entry = 'build'
else:
entry = 'buildWithParameters'
resp = self.handle_req('POST', entry, params=params, files=files)
return QueueItem(self, resp.headers['Location'])
Please let me know your comment, I can make PR with your suggestions if you think this make sense.
When using api4jenkins
with pytest, it may happen that the following exception occurs:
def unraisable_exception_runtest_hook() -> Generator[None, None, None]:
with catch_unraisable_exception() as cm:
yield
if cm.unraisable:
if cm.unraisable.err_msg is not None:
err_msg = cm.unraisable.err_msg
else:
err_msg = "Exception ignored in"
msg = f"{err_msg}: {cm.unraisable.object!r}\n\n"
msg += "".join(
traceback.format_exception(
cm.unraisable.exc_type,
cm.unraisable.exc_value,
cm.unraisable.exc_traceback,
)
)
> warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E pytest.PytestUnraisableExceptionWarning: Exception ignored in: <socket.socket fd=-1, family=10, type=1, proto=6>
E
E Traceback (most recent call last):
E File "/usr/lib64/python3.11/encodings/idna.py", line 155, in encode
E result = input.encode('ascii')
E ^^^^^^^^^^^^^^^^^^^^^
E ResourceWarning: unclosed <socket.socket fd=34, family=10, type=1, proto=6, laddr=('::1', 48440, 0, 0), raddr=('::1', 50001, 0, 0)>
This is because the http_client
in the Jenkins
class constructor (and probably the async version, too) isn't closed after being used. I think the garbage collector of python isn't working properly in this case because the jenkins object (instance) is being passed into all BaseItem
items as reference.
As a workaround, the http client can be closed manually:
jenkins_client = Jenkins(...)
# Do something with the client
client.get_job(...)
# Close the http client
jenkins_client.http_client.close()
but I'd suggest to wrap the http client in an (auto closing) context manager or something like that.
After #33
Can the limit of 100 jobs be documented ?
I spent quite a while debugging why I couldn't get a job which I knew was valid. Turns out it was older than 100 jobs.
Even better would be an optional parameter (default to 100) which forces the user to think and can define more if required.
I have configured the Jenkins instance to run on subpath using this configuration --prefix=$PREFIX (https://www.jenkins.io/doc/book/installing/initial-settings/#networking-parameters).
When i try to approve the Jobs, its failing with following error:
Sep 27 10:45:12 jenkins python[216706]: 2022-09-27 10:45:12,892 DEBUG POST: https://localhost/jenkins//jenkins/job/Test_QA_PL/3/input/D429835560e9194da64fefbc4517f23f/proceedEmpty with parameters: {'headers': {'Jenkins-Crumb': 'xxxx'}}
Sep 27 10:45:12 jenkins python[216706]: 2022-09-27 10:45:12,965 DEBUG https://localhost:443 "POST /jenkins//jenkins/job/Test_QA_PL/3/input/D429835560e9194da64fefbc4517f23f/proceedEmpty HTTP/1.1" 404 526
Sep 27 10:45:12 jenkins python[216706]: 2022-09-27 10:45:12,966 DEBUG Response: <Response [404]>
Sep 27 10:45:12 jenkins python[216706]: 2022-09-27 10:45:12,966 INFO sqlalchemy.engine.Engine ROLLBACK
Sep 27 10:45:12 jenkins python[216706]: 2022-09-27 10:45:12,966 INFO ROLLBACK
Sep 27 10:45:12 jenkins python[216706]: 2022-09-27 10:45:12,966 ERROR Exception on /jira [POST]
Sep 27 10:45:12 jenkins python[216706]: Traceback (most recent call last):
Sep 27 10:45:12 jenkins python[216706]: File "/opt/build_automator/venv/lib/python3.10/site-packages/api4jenkins/item.py", line 73, in handle_req
Sep 27 10:45:12 jenkins python[216706]: return self.jenkins.send_req(method, self.url + entry, **kwargs)
Sep 27 10:45:12 jenkins python[216706]: File "/opt/build_automator/venv/lib/python3.10/site-packages/api4jenkins/requester.py", line 28, in send
Sep 27 10:45:12 jenkins python[216706]: resp.raise_for_status()
Sep 27 10:45:12 jenkins python[216706]: File "/opt/build_automator/venv/lib/python3.10/site-packages/requests/models.py", line 960, in raise_for_status
Sep 27 10:45:12 jenkins python[216706]: raise HTTPError(http_error_msg, response=self)
Sep 27 10:45:12 jenkins python[216706]: requests.exceptions.HTTPError: 404 Client Error: Not Found for url: https://localhost/jenkins//jenkins/job/Test_QA_PL/3/input/D429835560e9194da64fefbc4517f23f/proceedEmpty
Sep 27 10:45:12 jenkins python[216706]: The above exception was the direct cause of the following exception:
Sep 27 10:45:12 jenkins python[216706]: Traceback (most recent call last):
Sep 27 10:45:12 jenkins python[216706]: File "/opt/build_automator/venv/lib/python3.10/site-packages/flask/app.py", line 2073, in wsgi_app
Sep 27 10:45:12 jenkins python[216706]: response = self.full_dispatch_request()
Sep 27 10:45:12 jenkins python[216706]: File "/opt/build_automator/venv/lib/python3.10/site-packages/flask/app.py", line 1518, in full_dispatch_request
Sep 27 10:45:12 jenkins python[216706]: rv = self.handle_user_exception(e)
Sep 27 10:45:12 jenkins python[216706]: File "/opt/build_automator/venv/lib/python3.10/site-packages/flask/app.py", line 1516, in full_dispatch_request
Sep 27 10:45:12 jenkins python[216706]: rv = self.dispatch_request()
Sep 27 10:45:12 jenkins python[216706]: File "/opt/build_automator/venv/lib/python3.10/site-packages/flask/app.py", line 1502, in dispatch_request
Sep 27 10:45:12 jenkins python[216706]: return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
Sep 27 10:45:12 jenkins python[216706]: File "/opt/build_automator/server.py", line 61, in jira_parse
Sep 27 10:45:12 jenkins python[216706]: jira_parser.parse(data)
Sep 27 10:45:12 jenkins python[216706]: File "/opt/build_automator/jira_parser.py", line 84, in parse
Sep 27 10:45:12 jenkins python[216706]: self.request_approved(jira_id,service,environment)
Sep 27 10:45:12 jenkins python[216706]: File "/opt/build_automator/jira_parser.py", line 142, in request_approved
Sep 27 10:45:12 jenkins python[216706]: if self.jenkins.approve_job(job_name):
Sep 27 10:45:12 jenkins python[216706]: File "/opt/build_automator/jenkins_utils.py", line 89, in approve_job
Sep 27 10:45:12 jenkins python[216706]: build.get_pending_input().submit()
Sep 27 10:45:12 jenkins python[216706]: File "/opt/build_automator/venv/lib/python3.10/site-packages/api4jenkins/input.py", line 43, in submit
Sep 27 10:45:12 jenkins python[216706]: return self.handle_req('POST', 'proceedEmpty')
Sep 27 10:45:12 jenkins python[216706]: File "/opt/build_automator/venv/lib/python3.10/site-packages/api4jenkins/item.py", line 76, in handle_req
Sep 27 10:45:12 jenkins python[216706]: raise ItemNotFoundError(
Sep 27 10:45:12 jenkins python[216706]: api4jenkins.exceptions.ItemNotFoundError: Not found proceedEmpty for item: <PendingInputAction: https://localhost/jenkins//jenkins/job/Test_QA_PL/3/input/D429835560e9194da64fefbc4517f23f/>
api4jenkins does not include version dependency for requests library -
it's not supported older version (at least requests 2.10)
api4jenkins should include version dependency
I am getting this error using api4jenkins 1.5 that I am not getting in 1.4. Is there anything special I need to do when using 1.5?
File "/usr/local/lib/python3.8/dist-packages/api4jenkins/queue.py", line 59, in get_build
for build in self.jenkins.nodes.iter_builds():
File "/usr/local/lib/python3.8/dist-packages/api4jenkins/node.py", line 54, in iter_builds
yield from _new_items(self.jenkins, builds)
File "/usr/local/lib/python3.8/dist-packages/api4jenkins/node.py", line 66, in _new_items
yield new_item(jenkins, 'api4jenkins.build', item)
File "/usr/local/lib/python3.8/dist-packages/api4jenkins/item.py", line 41, in func
raise AttributeError(f'{module} has no class {class_name}, '
AttributeError: <module 'api4jenkins.build' from '/usr/local/lib/python3.8/dist-packages/api4jenkins/build.py'> has no class PlaceholderExecutable, Patch new class with api4jenkins._patch_to
Hi there,
I upgraded from version 1.15 to 2.0 and get an issue, the method get_build() is missing.
def get_build_data_by_number(self, job_name: str, build_number: int):
""" Route Jenkins: Get build data by build number """
job_item = self.get_job(job_name)
if job_item:
build_item = job_item.get(build_number)
if build_item:
return build_item.api_json()
return False
How can I retreive information on a specific build from job?
Thanks
readthedocs.io, Examples, Folder, Create
It would be nice to see an example of a folder_xml
.
Thanks
https://api4jenkins.readthedocs.io/en/latest/user/example.html#folder
At first, the Jenkins API makes the connection well. However, when it gets to post, it changes.
Is it possible to make the Jenkins API just strictly follow the input parameter http://1.2.3.4:8080/jenkins
instead?
2022-11-01 16:35:10,635 DEBUG [ retry | from_int ] Converted retries value: 1 -> Retry(total=1, connect=None, read=None, redirect=None, status=None)
2022-11-01 16:35:10,635 DEBUG [ requester | send ] GET: http://1.2.3.4:8080/jenkins/crumbIssuer/api/json with parameters: {}
2022-11-01 16:35:10,638 DEBUG [ connectionpool | _new_conn ] Starting new HTTP connection (1): 1.2.3.4:8080
2022-11-01 16:35:10,643 DEBUG [ connectionpool | _make_request ] http://1.2.3.4:8080 "GET /jenkins/crumbIssuer/api/json HTTP/1.1" 200 155
2022-11-01 16:35:10,644 DEBUG [ requester | send ] Response: <Response [200]>
2022-11-01 16:35:10,645 DEBUG [ requester | send ] GET: http://1.2.3.4:8080/jenkins/ with parameters: {'headers': {'Jenkins-Crumb': '699fc00f48ee20ec273953d41cf2387239a30cc39219b55fff5849ce69e7e65d'}}
2022-11-01 16:35:10,673 DEBUG [ connectionpool | _make_request ] http://1.2.3.4:8080 "GET /jenkins/ HTTP/1.1" 200 11463
2022-11-01 16:35:10,675 DEBUG [ requester | send ] Response: <Response [200]>
2022-11-01 16:35:10,676 DEBUG [ requester | send ] GET: http://1.2.3.4:8080/jenkins/api/json with parameters: {'headers': {'Jenkins-Crumb': '699fc00f48ee20ec273953d41cf2387239a30cc39219b55fff5849ce69e7e65d'},
'params': {'depth': 0, 'tree': '_class'}}
2022-11-01 16:35:10,682 DEBUG [ connectionpool | _make_request ] http://1.2.3.4:8080 "GET /jenkins/api/json?depth=0&tree=_class HTTP/1.1" 200 48
2022-11-01 16:35:10,683 DEBUG [ requester | send ] Response: <Response [200]>
2022-11-01 16:35:10,683 DEBUG [ requester | send ] GET: http://1.2.3.4:8080/jenkins/api/json with parameters: {'headers': {'Jenkins-Crumb': '699fc00f48ee20ec273953d41cf2387239a30cc39219b55fff5849ce69e7e65d'},
'params': {'depth': 0, 'tree': 'jobs[name,url]'}}
2022-11-01 16:35:10,690 DEBUG [ connectionpool | _make_request ] http://1.2.3.4:8080 "GET /jenkins/api/json?depth=0&tree=jobs%5Bname%2Curl%5D HTTP/1.1" 200 964
2022-11-01 16:35:10,691 DEBUG [ requester | send ] Response: <Response [200]>
2022-11-01 16:35:10,691 DEBUG [ requester | send ] POST: http://docker.mywebsite.com/jenkins/job/JENKINS_TASK/buildWithParameters with parameters: {'headers': {'Jenkins-Crumb': '699fc00f48ee20ec273953d41cf2387239a30cc39219b55fff5849ce69e7e65d'},
'params': {'x': 'x',
'y': y,
'z': 'z',
'a': 'a',
'b': 'b'}}
2022-11-01 16:35:10,693 DEBUG [ connectionpool | _new_conn ] Starting new HTTP connection (1): docker.mywebsite.com:80
...
In the last line (and the line before): 2022-11-01 16:35:10,693 DEBUG [ connectionpool | _new_conn ] Starting new HTTP connection (1): docker.mywebsite.com:80
You can see, instead of the IP address + 8080 port number, it changes.
I also tried with Jenkins(jenkins_url, auth=(user, token), allow_redirects=False, verify=False)
but doubting I did it right and/or if it did anything. I got the kwargs from here which redirected me to here.
I saw this previous GitHub issue, but unsure how to understand the conversation at the end -- a bit vague.
api4jenkins/api4jenkins/node.py
Line 57 in 22e3191
Documented here: https://www.jenkins.io/doc/book/managing/built-in-node-migration/
Checking the displayName and replacing, fixes the issue
for item in self.api_json(tree='computer[displayName]')['computer']:
if (item['displayName'] == 'Built-In Node'):
item['displayName'] = '(built-in)'
There is probably a nicer way to do this with 'replace()'
Hi ,
Have anything else possible added proxy items when creating Jenkins(url=, proxy='') like these. Because of some landscaped requirement setup proxy. Thanks.
proxies = {
'http': 'http://proxy.example.com:8080',
'https': 'http://secureproxy.example.com:8090',
}
url = 'http://mywebsite.com/example'
response = requests.post(url, proxies=proxies)
Currently api4jenkins supports to manage system and folder based credentials, which must be in the default domain(_).
It would be great if api4jenkins could manage credentials in different domains and if it could even manage credentials domains.
Another Python package, python-jenkins, can handle credentials in all domains, but it can not manage system credentials and credentials in GitHub organization folders. Therefore I am using now api4jenkins.
I brought up the other package just to point out that credentials domains managements could be implemented here too.
In my application I am using the Python logging library and it was not having problems with api4jenkins till the version v1.15.0
. As soon as I have started using a newer version, I get such messages in my logs for all operations:
2023-12-12 16:09:36 INFO HTTP Request: GET https://jenkins.mycompany.com/crumbIssuer/api/json "HTTP/1.1 200 OK"
2023-12-12 16:09:36 INFO HTTP Request: HEAD https://jenkins.mycompany.com/ "HTTP/1.1 200 OK"
2023-12-12 16:09:36 INFO HTTP Request: GET https://jenkins.mycompany.com/user/myuser/api/json?depth=0 "HTTP/1.1 200 OK"
2023-12-12 16:09:36 INFO HTTP Request: GET https://jenkins.mycompany.com/user/myuser/api/json?depth=0&tree=id "HTTP/1.1 200 OK"
2023-12-12 16:09:36 INFO HTTP Request: GET https://jenkins.mycompany.com/user/myuser/api/json?depth=0&tree=absoluteUrl "HTTP/1.1 200 OK"
2023-12-12 16:09:36 INFO HTTP Request: GET https://jenkins.mycompany.com/user/myuser/api/json?depth=0&tree=fullName "HTTP/1.1 200 OK"
It looks like sometimes these logs even lead to a The read operation timed out
error which interrupts my application. I have tried to control the logger as follows:
import logging
...
jenkins_logger = logging.getLogger('api4jenkins')
jenkins_logger.setLevel(logging.CRITICAL)
but whatever log level I set, I still get the same high amount of log messages. The last 2 rows above were not necessary in the v1.15.0
version.
I am using Python 3.10.13
and I have encountered this issue with api4jenkins v2.0.0
, v2.0.1
and v2.0.2
. These versions have 3 loggers: api4jenkins.item, api4jenkins and api4jenkins.http. Instead the v1.15.0
version has 2 loggers: api4jenkins.requester and api4jenkins.
Hi, I got following error, have anything else parameters to false check certificates?
Max retries exceeded with url: /crumbIssuer/api/json (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1129)')))
I want to store a Jenkins credential of type secret file as follows:
my_xml = '''<org.jenkinsci.plugins.plaincredentials.impl.FileCredentialsImpl plugin="plain-credentials">
<id>###CREDENTIAL_ID###</id>
<description>###CREDENTIAL_DESC###</description>
<fileName>###SECRET_FILE_NAME###</fileName>
<secretBytes>###SECRET_FILE_BYTES###</secretBytes>
</org.jenkinsci.plugins.plaincredentials.impl.FileCredentialsImpl>'''
secret_file_path = '/path/to/my/secret/file'
secret_file_name = os.path.basename(secret_file_path)
with open(secret_file_path, 'r') as secret_file:
secret_file_string = secret_file.read()
my_xml = my_xml.replace('###CREDENTIAL_ID###', 'my-secret-file-cred-id')
my_xml = my_xml.replace('###CREDENTIAL_DESC###', 'My secret file description')
my_xml = my_xml.replace('###SECRET_FILE_NAME###', secret_file_name)
my_xml = my_xml.replace('###SECRET_FILE_BYTES###', secret_file_string)
folder = j.get_job('SOME_JENKINS_FOLDER')
folder.credentials.create(my_xml)
The Jenkins credential is successfully stored, but when I try to use it in my Jenkins pipeline this error is returned:
error: error loading config file "/root/.kube/config": yaml: invalid leading UTF-8 octet
The file in this case is a Kubeconfig in JSON format. In order to exclude that the file is the problem, I have then tried to upload manually the file via the GUI and the pipeline reads the secret file successfully and it runs without encountering the same problem.
I have seen this article about somebody solving the issue when using the API via curl
, but I could not find anything helpful when creating the XML file like this case.
Did anybody face this issue? Is there a known solution for this matter? Thanks in advance!
Hi, I just want to know if this library is thread-safe, thanks
Hey,
first thank you for this helpful lib.
There is the first error message:
AttributeError: <module 'api4jenkins.view' from '<user>/test/lib/python3.8/site-packages/api4jenkins/view.py'> has no class SectionedView to describe
<url>/view/CI%20Builds%20(TFS)/, patch new class with api4jenkins._patch_to,
see: https://api4jenkins.readthedocs.io/en/latest/user/example.html#patch
Then I tried to fix it with this code snippet:
class SectionedView(Jenkins):
pass
def test():
jenkins = Jenkins(jenkins_url, auth=(username, password))
_patch_to('api4jenkins.view', SectionedView)
for view in jenkins.views:
print(view)
Then the following error is:
item = {'_class': 'hudson.plugins.sectioned_view.SectionedView', 'name': 'CI Builds (TFS)', 'url': '<url>/view/CI%20Builds%20(TFS)/'}
def func(jenkins, module, item):
class_name = delimiter.split(item['_class'])[-1]
module = import_module(module)
if not hasattr(module, class_name):
msg = f'''{module} has no class {class_name} to describe
{item["url"]}, patch new class with api4jenkins._patch_to,
see: https://api4jenkins.readthedocs.io/en/latest/user/example.html#patch'''
raise AttributeError(msg)
_class = getattr(module, class_name)
return _class(jenkins, item['url'])
TypeError: __init__() takes 2 positional arguments but 3 were given
Do I something wrong?
Kind regards,
Benedikt
Hello,
How can we get the 'AuthorizationMatrixProperty' (permissions) for each folder configured with matrix-authorization ?
We loop through each folder name, get the config.xml and extract the permissions from the xml tree?
# folder config.xml output example:
<com.cloudbees.hudson.plugins.folder.properties.AuthorizationMatrixProperty>
<inheritanceStrategy class="org.jenkinsci.plugins.matrixauth.inheritance.InheritParentStrategy"/>
<permission>com.cloudbees.plugins.credentials.CredentialsProvider.Create:user1example</permission>
.........................................
I want to disable a multi-branch pipeline, but when I use disable()
, I find the following problem
buildable
attributebuildable
property of the master branch is still True
multi_branch_pipeline = jenkins.get_job("test_multi_branch")
multi_branch_master = jenkins.get_job("test_multi_branch/master")
print(multi_branch_pipeline.disable())
# print(multi_branch_pipeline.buildable) # This will raise an exception `AttributeError: 'WorkflowMultiBranchProject' object has no attribute 'buildable'`
print(multi_branch_master.buildable) # True
So how can I get the status of a multi-branch pipeline
result:
{"_class":"net.uaznia.lukanus.hudson.plugins.gitparameter.model.ItemsErrorModel","errors":[],"values":[{"name":"4b91af67 2020-10-25 18:11 xxxxx [email protected] 1. xxxxxxxxxxxxxxxxxxxx","value":"4b91af1111115df6212f1fdsfdsaf4223826f43434"}]}
Thanks for your awesome jenkins python wrapper.
I wonder know could we get the build parameters from Build class?
api4jenksin version = 1.5.1
Jenkins version = 2.249.3 (open source install)
I'm triggering builds for 2 different jobs and I'm passing in a non 0 delay parameter to one or both of them. The order in which I trigger these 2 jobs affects the get_build() function of QueueItem.
Code to trigger a job. Takes job name, existing Jenkins server object and optional delay parameter.
trigger_build(job_name, jenkins_server, delay='0sec'):
params = {
'delay': delay
}
return jenkins_server.build_job(job_name, **params)
Case 1: Trigger delayed job first. No issue.
build_jobs = {}
build_jobs['first'] = trigger_build('Builds/App1/main', jenkins_server, '20sec')
build_jobs['second'] = trigger_build('Builds/App2/main', jenkins_server)
for x in build_jobs:
print ("{} type is {} url is {}".format(x, type(build_jobs[x]), build_jobs[x].get_job().url))
while True:
print('Waiting for queue to clear....')
time.sleep(5)
q_is_empty = True
for job in build_jobs:
if not build_jobs[job].get_build():
print("{} is still queued".format(job))
q_is_empty = False
break
if q_is_empty:
break
print('Build queue cleared.\n')
for x in build_jobs:
job = build_jobs[x].get_build().get_job()
print("{} = {}".format(x, job.url))
Output for case 1,
first type is <class 'api4jenkins.queue.QueueItem'>, https://my.jenkins.server/job/Builds/job/App1/job/main/
second type is <class 'api4jenkins.queue.QueueItem'>, https://my.jenkins.server/job/Builds/job/App2/job/main/
Waiting for queue to clear....'
first is still queued
first is still queued
first is still queued
Build queue cleared
first = https://my.jenkins.server/job/Builds/job/App1/job/main/
second = https://my.jenkins.server/job/Builds/job/App2/job/main/
Case 2: Trigger delayed job last. I lose reference to the second job
Simply move the delay param to the second job,
build_jobs = {}
build_jobs['first'] = trigger_build('Builds/App1/main', jenkins_server)
build_jobs['second'] = trigger_build('Builds/App2/main', jenkins_server, '20sec')
The rest of the code stays the same but I get the following output,
first type is <class 'api4jenkins.queue.QueueItem'>, https://my.jenkins.server/job/Builds/job/App1/job/main/
second type is <class 'api4jenkins.queue.QueueItem'>, https://my.jenkins.server/job/Builds/job/App2/job/main/
Waiting for queue to clear....' <---- No waiting on the delayed job like in the first case.
Build queue cleared
first = https://my.jenkins.server/job/Builds/job/App1/job/main/
second = https://my.jenkins.server/job/Builds/job/App1/job/main/ <---- This is the URL to the first job.
Case 3: Both jobs have same delay OR the first job has a longer delay than the second job. No issue.
build_jobs = {}
build_jobs['first'] = trigger_build('Builds/App1/main', jenkins_server, '20sec')
build_jobs['second'] = trigger_build('Builds/App2/main', jenkins_server, '20sec')
The output is identical to use case 1.
Case 4: The second job has a longer delay than the first job
build_jobs = {}
build_jobs['first'] = trigger_build('Builds/App1/main', jenkins_server, '10sec')
build_jobs['second'] = trigger_build('Builds/App2/main', jenkins_server, '20sec')
The output is similar to use case 2.
first type is <class 'api4jenkins.queue.QueueItem'>, https://my.jenkins.server/job/Builds/job/App1/job/main/
second type is <class 'api4jenkins.queue.QueueItem'>, https://my.jenkins.server/job/Builds/job/App2/job/main/
Waiting for queue to clear....'
first is still queued
first is still queued
Build queue cleared
first = https://my.jenkins.server/job/Builds/job/App1/job/main/
second = https://my.jenkins.server/job/Builds/job/App1/job/main/ <---- This is the URL to the first job.
Force build with API http://<ci-host>/job/<jobname>/buildWithParameters
instead http://<ci-host>/job/<jobname>/build
line 59 in queue.py
if int(build.queue_id) + 1 == self.id:
this rule does not take effect all the time, but I don't find the patterns either……
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.