如何使用标准 Python 库通过文件参数触发经过身份验证的 Jenkins 作业

发布于 2024-12-19 19:12:43 字数 1054 浏览 2 评论 0 原文

目前,我们正在 PycURL 的帮助下从 Python 脚本触发 Jenkins 作业。然而,我们希望摆脱 PycURL 依赖,但迄今为止收效甚微。让我们的场景变得更加复杂的是我们需要发布一个文件作为参数。我们当前用于发布请求的 PycURL 逻辑如下所示:

url = "https://myjenkins/job/myjob/build"
with contextlib.closing(pycurl.Curl()) as curl:
    curl.setopt(pycurl.URL, url)
    curl.setopt(pycurl.USERPWD, "myuser:mypassword")
    curl.setopt(pycurl.SSL_VERIFYPEER, False)
    curl.setopt(pycurl.SSL_VERIFYHOST, False)
    curl.setopt(pycurl.FAILONERROR, True)
    data = [
            ("name", "integration.xml"),
            ("file0", (pycurl.FORM_FILE, "integration.xml")),
            ("json", "{'parameter': [{'name': 'integration.xml', 'file': 'file0'}]}"),
            ("Submit", "Build"),
            ]
    curl.setopt(pycurl.HTTPPOST, data)
    try:
        curl.perform()
    except pycurl.error, err:
        raise JenkinsTriggerError(curl.errstr())

我们如何用标准 Python 库中的功能来替换它?

我们之前尝试过,但不得不放弃,因为我们看不到如何成功上传文件,正如您可以从 我关于这个问题的问题

We are currently triggering Jenkins jobs from a Python script with the help of PycURL. We would like, however, to get rid of the PycURL dependency, but have had little success so far. What makes our scenario more complicated is that we need to post a file as a parameter. Our current PycURL logic for posting the request looks as follows:

url = "https://myjenkins/job/myjob/build"
with contextlib.closing(pycurl.Curl()) as curl:
    curl.setopt(pycurl.URL, url)
    curl.setopt(pycurl.USERPWD, "myuser:mypassword")
    curl.setopt(pycurl.SSL_VERIFYPEER, False)
    curl.setopt(pycurl.SSL_VERIFYHOST, False)
    curl.setopt(pycurl.FAILONERROR, True)
    data = [
            ("name", "integration.xml"),
            ("file0", (pycurl.FORM_FILE, "integration.xml")),
            ("json", "{'parameter': [{'name': 'integration.xml', 'file': 'file0'}]}"),
            ("Submit", "Build"),
            ]
    curl.setopt(pycurl.HTTPPOST, data)
    try:
        curl.perform()
    except pycurl.error, err:
        raise JenkinsTriggerError(curl.errstr())

How can we replace this with facilities from the standard Python library?

We've tried before, but had to give up as we could not see how to upload files successfully, as you can see from my question on that issue.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

妄司 2024-12-26 19:12:43

我们只能借助 requests 库来做到这一点。

import requests

payload = ( ('file0', open("FILE_LOCATION_ON_LOCAL_MACHINE", "rb")), 
            ('json', '{ "parameter": [ { 
                                         "name":"FILE_LOCATION_AS_SET_IN_JENKINS", 
                                         "file":"file0" }]}' ))

resp = requests.post("JENKINS_URL/job/JOB_NAME/build", 
                   auth=('username','password'), 
                   headers={"Jenkins-Crumb":"9e1cf46405223fb634323442a55f4412"}, 
                   files=payload )

如果需要,可以使用 Jekins-Crumb 获取:

requests.get('http://username:password@JENKINS_URL/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)')

We can do it with the help of requests library only.

import requests

payload = ( ('file0', open("FILE_LOCATION_ON_LOCAL_MACHINE", "rb")), 
            ('json', '{ "parameter": [ { 
                                         "name":"FILE_LOCATION_AS_SET_IN_JENKINS", 
                                         "file":"file0" }]}' ))

resp = requests.post("JENKINS_URL/job/JOB_NAME/build", 
                   auth=('username','password'), 
                   headers={"Jenkins-Crumb":"9e1cf46405223fb634323442a55f4412"}, 
                   files=payload )

Jekins-Crumb if required can be obtained using:

requests.get('http://username:password@JENKINS_URL/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)')
放手` 2024-12-26 19:12:43

我找到了一个解决方案,使用 requestsurllib3 库。不完全标准,但比 PycURL 依赖项更轻量。应该可以直接使用请求来执行此操作(避免 urllib3 部分),但我遇到了一个错误。

import urllib3, requests, json

url = "https://myjenkins.com/job/myjob"

params = {"parameter": [
    {"name": "integration.xml", "file": "file0"},
    ]}
with open("integration.xml", "rb") as f:
    file_data = f.read()
data, content_type = urllib3.encode_multipart_formdata([
    ("file0", (f.name, file_data)),
    ("json", json.dumps(params)),
    ("Submit", "Build"),
    ])
resp = requests.post(url, auth=("myuser", "mypassword"), data=data,
        headers={"content-type": content_type}, verify=False)
resp.raise_for_status()

I found a solution, using the requests and urllib3 libraries. Not entirely standard, but more lightweight than the PycURL dependency. It should be possible to do this directly with requests (avoiding the urllib3 part), but I ran into a bug.

import urllib3, requests, json

url = "https://myjenkins.com/job/myjob"

params = {"parameter": [
    {"name": "integration.xml", "file": "file0"},
    ]}
with open("integration.xml", "rb") as f:
    file_data = f.read()
data, content_type = urllib3.encode_multipart_formdata([
    ("file0", (f.name, file_data)),
    ("json", json.dumps(params)),
    ("Submit", "Build"),
    ])
resp = requests.post(url, auth=("myuser", "mypassword"), data=data,
        headers={"content-type": content_type}, verify=False)
resp.raise_for_status()
臻嫒无言 2024-12-26 19:12:43

如果您熟悉 python,那么您可以使用官方网站提供的 jenkins REST APT python 包装器。 查看此链接

使用这个 python 包装器触发构建非常容易。这是我的示例:

#!/usr/bin/python
import jenkins

if __name == "main":
    j = jenkins.Jenkins(jenkins_server_url, username="youruserid", password="yourtoken")
    j.build_job(yourjobname,{'param1': 'test value 1', 'param2': 'test value 2'},
                    {'token': "yourtoken"})

对于那些不知道在哪里可以找到令牌的人,以下是方法:

登录詹金斯->从网页顶部单击您的用户 ID ->
配置 -> 显示 API 令牌...

享受它。

If you are familiar with python, then you can use the jenkins REST APT python wrapper provided by the official site. see this link.

Trigger a build is unbelievably easy by using this python wrapper. Here is my example:

#!/usr/bin/python
import jenkins

if __name == "main":
    j = jenkins.Jenkins(jenkins_server_url, username="youruserid", password="yourtoken")
    j.build_job(yourjobname,{'param1': 'test value 1', 'param2': 'test value 2'},
                    {'token': "yourtoken"})

For those who don't know where to find the token, here is how:

login to jenkins -> click your userid from the top of the webpage ->
Configure ->Show API Token...

Enjoy it.

不气馁 2024-12-26 19:12:43

可能看起来像这样:

url = "https://myjenkins/job/myjob/build"
req = urllib2.Request(url)

auth = 'Basic ' + base64.urlsafe_b64encode("myuser:mypassword")
req.add_header('Authorization', auth)

with open("integration.xml", "r") as f:
  file0 = f.read()
  data = {
            "name": "integration.xml",
            "file0": file0,
            "json": "{'parameter': [{'name': 'integration.xml', 'file': 'file0'}]}",
            "Submit": "Build"
         }
  req.add_data(urllib.urlencode(data))

urllib2.urlopen(req)

抱歉,我没有安装 Jenkins 来测试它。

Probably it can look something like this:

url = "https://myjenkins/job/myjob/build"
req = urllib2.Request(url)

auth = 'Basic ' + base64.urlsafe_b64encode("myuser:mypassword")
req.add_header('Authorization', auth)

with open("integration.xml", "r") as f:
  file0 = f.read()
  data = {
            "name": "integration.xml",
            "file0": file0,
            "json": "{'parameter': [{'name': 'integration.xml', 'file': 'file0'}]}",
            "Submit": "Build"
         }
  req.add_data(urllib.urlencode(data))

urllib2.urlopen(req)

Sorry, I don't have installed Jenkins around to test it out.

拥抱我好吗 2024-12-26 19:12:43

(2024.01) 让我在经过一天的尝试和错误之后提供迄今为止最好的解决方案。

  • Python 3.8.11
  • Jenkins 2.426.2

在此处输入图像描述

import requests

ENDPOINT = 'https://$JENKINS_SERVICE/job/$JENKINS_JOB'
AUTH = ('johndow', 'johndowpwd')

def post_build():
    with open('example.txt', 'rb') as fs:
        r = requests.post(f'{ENDPOINT}/buildWithParameters',
                          auth=AUTH,
                          files={'hey.txt': fs},
                          params={'HI': 'abc', 'HELLO': 'xyz'})
    r.raise_for_status()

注意必须声明文件关闭,参考:https://stackoverflow.com/a/52396494/8013269

(2024.01) Let me provide the best solution so far after my eniter day of try and error.

  • Python 3.8.11
  • Jenkins 2.426.2

enter image description here

import requests

ENDPOINT = 'https://$JENKINS_SERVICE/job/$JENKINS_JOB'
AUTH = ('johndow', 'johndowpwd')

def post_build():
    with open('example.txt', 'rb') as fs:
        r = requests.post(f'{ENDPOINT}/buildWithParameters',
                          auth=AUTH,
                          files={'hey.txt': fs},
                          params={'HI': 'abc', 'HELLO': 'xyz'})
    r.raise_for_status()

Note that file close must be stated, refer to: https://stackoverflow.com/a/52396494/8013269

再可℃爱ぅ一点好了 2024-12-26 19:12:43

这是与 aknuds1 答案类似的版本,其中 test_result 是 xml 字符串:

j_string = "{'parameter': [{'name': 'integration_tests.xml', 'file': 'someFileKey0'}]}"
data = {
          "name": "integration_tests.xml",
          "json": j_string, 
        }
for xml_string in tests.values():
    post_form_result = requests.post('http://jenkins/job/deployment_tests/build',
                                     data=data,
                                     files={'someFileKey0': xml_string})
    print(post_form_result.status_code)

猜测一下,附加参数将作为 json 字符串数组或附加文件等的一部分传入。如果有,请告诉我情况确实如此,如果我发现的话,我会更新这个答案。该解决方案可以很好地触发 JUnit 测试。

版本:

master* $ pip show requests                                                                                                                                                                      [21:45:05]
Name: requests
Version: 2.12.3
Summary: Python HTTP for Humans.
Home-page: http://python-requests.org
Author: Kenneth Reitz
Author-email: [email protected]
License: Apache 2.0
Location: /usr/local/lib/python2.7/site-packages

Here is a similar version to aknuds1 answer where test_result is the xml string:

j_string = "{'parameter': [{'name': 'integration_tests.xml', 'file': 'someFileKey0'}]}"
data = {
          "name": "integration_tests.xml",
          "json": j_string, 
        }
for xml_string in tests.values():
    post_form_result = requests.post('http://jenkins/job/deployment_tests/build',
                                     data=data,
                                     files={'someFileKey0': xml_string})
    print(post_form_result.status_code)

Taking a guess, additional parameters would be passed in as part of the json string array, or additional files, etc. Let me know if this is the case, also, if I find out, i'll update this answer. This solution worked nicely to trigger JUnit tests.

Version:

master* $ pip show requests                                                                                                                                                                      [21:45:05]
Name: requests
Version: 2.12.3
Summary: Python HTTP for Humans.
Home-page: http://python-requests.org
Author: Kenneth Reitz
Author-email: [email protected]
License: Apache 2.0
Location: /usr/local/lib/python2.7/site-packages
得不到的就毁灭 2024-12-26 19:12:43

我使用的另一个替代方案:

import requests
import json
url = "https://myjenkins/job/myjob/build"
payload = {'key1': 'value1', 'key2': 'value2'}
resp = requests.post(url, params=payload, auth=("username", "password"),verify=False)
json_data = json.loads(resp.text)

有关更多详细信息,您可以参考:提出请求

Another Alternative that I used :

import requests
import json
url = "https://myjenkins/job/myjob/build"
payload = {'key1': 'value1', 'key2': 'value2'}
resp = requests.post(url, params=payload, auth=("username", "password"),verify=False)
json_data = json.loads(resp.text)

For more details you can refer :Make a Request

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文