在json解析jenkins凭证api错误时,Ansible啜饮私钥?

时间:2018-01-22 17:02:33

标签: python jenkins ansible jenkins-api slurp

我有jenkins设置,现在我想将节点添加到jenkins,我正在按照How-to-Connect-to-Remote-SSH-Slaves中的步骤进行操作。

使用slave node私钥创建凭证的步骤。我尝试使用ansible的jenkins api来创建它。

playbook中的任务是

- name: Read private key file content of slave1
  slurp:
      src: "{{ ansible_env.HOME }}/.ssh/slave1"
  register: private_key_file
  tags:
      - credential

- name: Add credential to add node
  uri:
      body: |
          json={
              "": "0",
              "credentials": {
                "scope": "GLOBAL",
                "id": "jenkins_linux_slave1_auth",
                "username": "jenkins",
                "password": "",
                "privateKeySource": {
                  "stapler-class": "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource",
                  "privateKey": "{{ private_key_file['content'] | b64decode }}",
                },
                "description": "Jenkins Linux Slave1 Authentication",
                "stapler-class": "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"
              }
            }
      force_basic_auth: yes
      method: POST
      password: "{{ jenkins_user_token }}"
      status_code: 302
      url: "{{ jenkins_url }}/credentials/store/system/domain/_/createCredentials"
      user: "{{ jenkins_user }}"
      validate_certs: no
  tags:
      - credential

但这失败了

$ ansible-playbook -i hosts jenkins_config.yaml --verbose -u root --ask-pass -b -e "jenkins_user=admin" -e "jenkins_user_token=admin" --tags credential
Using /root/ansible_playbooks/ansible.cfg as config file
SSH password:

PLAY [jenkins_servers] ***************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [jenkins_config : Read private key file content of slave1] **********************************************************************************************************************************************************************
ok: [localhost] => {"changed": false, "content": "Content", "encoding": "base64", "source": "/root/.ssh/slave1"}

TASK [jenkins_config : Add credential to add node] ***********************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"cache_control": "no-cache,no-store,must-revalidate", "changed": false, "connection": "close", "content": "\n\n\n\n\n  \n  <!DOCTYPE html><html><head resURL=\"/static/92560838\" data-rooturl=\"\" data-resurl=\"/static/92560838\">\n    \n\n    <title>Jenkins [Jenkins]</title><link rel=\"stylesheet\" href=\"/static/92560838/css/layout-common.css\" type=\"text/css\" /><link rel=\"stylesheet\" href=\"/static/92560838/css/style.css\" type=\"text/css\" /><link rel=\"stylesheet\" href=\"/static/92560838/css/color.css\" type=\"text/css\" /><link rel=\"stylesheet\" href=\"/static/92560838/css/responsive-grid.css\" type=\"text/css\" /><link rel=\"shortcut icon\" href=\"/static/92560838/favicon.ico\" type=\"image/vnd.microsoft.icon\" /><link color=\"black\" rel=\"mask-icon\" href=\"/images/mask-icon.svg\" /><script>var isRunAsTest=false; var rootURL=\"\"; var resURL=\"/static/92560838\";</script><script src=\"/static/92560838/scripts/prototype.js\" type=\"text/javascript\"></script><script src=\"/static/92560838/scripts/behavior.js\" type=\"text/javascript\"></script><script src='/adjuncts/92560838/org/kohsuke/stapler/bind.js' type='text/javascript'></script><script src=\"/static/92560838/scripts/yui/yahoo/yahoo-min.js\"></script><script src=\"/static/92560838/scripts/yui/dom/dom-min.js\"></script><script src=\"/static/92560838/scripts/yui/event/event-min.js\"></script><script src=\"/static/92560838/scripts/yui/animation/animation-min.js\"></script><script src=\"/static/92560838/scripts/yui/dragdrop/dragdrop-min.js\"></script><script src=\"/static/92560838/scripts/yui/container/container-min.js\"></script><script src=\"/static/92560838/scripts/yui/connection/connection-min.js\"></script>
"content_length": "27072", "content_type": "text/html;charset=utf-8", "date": "Mon, 22 Jan 2018 15:58:04 GMT", "expires": "Thu, 01 Jan 1970 00:00:00 GMT", "msg": "Status code was not [302]: HTTP Error 500: Server Error", "redirected": false, "server": "Jetty(9.4.z-SNAPSHOT)", "set_cookie": "JSESSIONID.8c551130=node0v7u4nqouxb1l1kcnd5139in7616.node0;Path=/;Secure;HttpOnly", "status": 500, "url": "http://localhost:8080/credentials/store/system/domain/_/createCredentials", "x_content_type_options": "nosniff", "x_frame_options": "sameorigin", "x_hudson": "1.395", "x_hudson_theme": "default", "x_instance_identity": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgORb1hlBOGx2LlN77veNlsGhwykedmrM+XqbHh0Fq4UGHQKhFicOXSPKiuOr4XpfWRZtYAy7jrY59cCF4So2qHionFUBjQespaALVC+aWQC3qIaZC4NlDgZXz+xQCFFrgW8G2iX2DA5kbPuwuIsv4WlgWvk8Z3kNmAxr16xhRq1R+RmdtVnmTaRyZiHdyQXdVpNHuYzITHfzUyIVIa8elbylS2CgDBMKRasxf7ewX++5Qp5rM5OzDbb5QLAueDhoyjAN2aA+jibUfYKoO7rwgpO3zMbIxuT9SKI7DMM7+TOEDQaH9SF0n+l/WXqpN6PLur9/o/10gsPghMXaV//KpQIDAQAB", "x_jenkins": "2.89.3", "x_jenkins_session": "92560838"}
    to retry, use: --limit @/root/ansible_playbooks/jenkins_config.retry

PLAY RECAP ***************************************************************************************************************************************************************************************************************************
localhost : ok=2    changed=0    unreachable=0    failed=1

我检查了jenkins日志,它显示了json解析的错误。

Jan 22, 2018 11:02:17 AM org.eclipse.jetty.server.handler.ContextHandler$Context log
WARNING: Error while serving http://localhost:8080/credentials/store/system/domain/_/createCredentials
java.lang.reflect.InvocationTargetException
    at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:347)
    at org.kohsuke.stapler.interceptor.RequirePOST$Processor.invoke(RequirePOST.java:52)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: javax.servlet.ServletException: Failed to parse JSON:{
    "": "0",
    "credentials": {
      "scope": "GLOBAL",
      "id": "jenkins_linux_slave1_auth",
      "username": "jenkins",
      "password": "",
      "privateKeySource": {
        "stapler-class": "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource",
        "privateKey": "-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
<MULTI LINE PRIVATE KEY>
-----END RSA PRIVATE KEY-----
",
      },
      "description": "Jenkins Linux Slave1 Authentication",
      "stapler-class": "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"
    }
  }

    at org.kohsuke.stapler.RequestImpl.getSubmittedForm(RequestImpl.java:1021)
    at com.cloudbees.plugins.credentials.CredentialsStoreAction$DomainWrapper.doCreateCredentials(CredentialsStoreAction.java:832)
    at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:627)
    at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:343)
    ... 84 more
Caused by: net.sf.json.JSONException: Unterminated string at character 365 of {
    "": "0",
    "credentials": {
      "scope": "GLOBAL",
      "id": "jenkins_linux_slave1_auth",
      "username": "jenkins",
      "password": "",
      "privateKeySource": {
        "stapler-class": "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource",
        "privateKey": "-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
<MULTI LINE PRIVATE KEY>
-----END RSA PRIVATE KEY-----
",
      },
      "description": "Jenkins Linux Slave1 Authentication",
      "stapler-class": "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"
    }
  }
    at net.sf.json.util.JSONTokener.syntaxError(JSONTokener.java:499)
    at net.sf.json.util.JSONTokener.nextString(JSONTokener.java:237)
    at net.sf.json.util.JSONTokener.nextValue(JSONTokener.java:345)
    at net.sf.json.JSONObject._fromJSONTokener(JSONObject.java:955)
    at net.sf.json.JSONObject.fromObject(JSONObject.java:156)
    at net.sf.json.util.JSONTokener.nextValue(JSONTokener.java:348)
    at net.sf.json.JSONObject._fromJSONTokener(JSONObject.java:955)
    at net.sf.json.JSONObject.fromObject(JSONObject.java:156)
    at net.sf.json.util.JSONTokener.nextValue(JSONTokener.java:348)
    at net.sf.json.JSONObject._fromJSONTokener(JSONObject.java:955)
    at net.sf.json.JSONObject._fromString(JSONObject.java:1145)
    at net.sf.json.JSONObject.fromObject(JSONObject.java:162)
    at net.sf.json.JSONObject.fromObject(JSONObject.java:132)
    at org.kohsuke.stapler.RequestImpl.getSubmittedForm(RequestImpl.java:1019)
    ... 87 more

如果我将私有文件的内容手动复制到有效负载中的privateKey,它可以正常工作。

复制文件内容与slurp['content]|b64decode之间的区别是什么?

2 个答案:

答案 0 :(得分:1)

  • 私钥包含需要转义以生成有效JSON的换行符。
  • privateKey字段后面有一个多余的逗号,您需要删除它

试试这个:

...
body: |
    json={
        "": "0",
        "credentials": {
          "scope": "GLOBAL",
          "id": "jenkins_linux_slave1_auth",
          "username": "jenkins",
          "password": "",
          "privateKeySource": {
            "stapler-class": "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource",
            "privateKey": {{ private_key_file['content'] | b64decode | tojson }}
          },
          "description": "Jenkins Linux Slave1 Authentication",
          "stapler-class": "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"
        }
      }
...

答案 1 :(得分:0)

我有同样的问题。

使用slurp获取私钥并传递值时,出现错误。

完成任务:

- name: Get private key vagrant
           slurp:
               src: '{{slave_linux_jenkins_private_key}}'
           register: private_key_file
        
        - name: Add credential to Node
          uri:
            url: "{{master_url}} / credentials / store / system / domain / _ / createCredentials"
            user: "{{master_username}}"
            password: "fooo"
            method: POST
            status_code: 302
            force_basic_auth: true
            body_format: json
        
            body: |
              json = {
                "": "0",
                "credentials": {
                "scope": "GLOBAL",
                "id": "{{slave_linux_jenkins_cred_id}}",
                "username": "{{slave_linux_jenkins_username}}",
                "password": "",
                "privateKeySource": {
                  "stapler-class": "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey $ DirectEntryPrivateKeySource",
                  "privateKey": "{{private_key_file ['content'] | b64decode | replace ('\ n', '')}}"
                },
                "description": "Node app-protheus",
                "stapler-class": "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"
                }
              }
    

我通过以下方式进行测试:

"privateKey": "{{private_key_file ['content'] | b64decode | replace ('\ n', '')}}"
    "privateKey": "{{private_key_file ['content'] | b64decode | to_json}}"

错误:

fatal: [protheus]: FAILED! => {"cache_control": "must-revalidate,no-cache,no-store", "changed": false, "connection": "close", "content": "html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/>\n<title>Error 400 Nothing is submitted</title>\n</head>\n<body><h2>HTTP ERROR 400 Nothing is submitted</h2>\n<table>\n<tr><th>URI:</th<td>/credentials/store/system/domain/_/createCredentials</td></tr>\n<tr><th>STATUS:</th><td>400</td></tr>\n<tr><th>MESSAGE:</th><td>Nothing is submitted</td></tr>\n<tr><th>SERVLET:</th><td>Stapler</td></tr>\n</table>\n<hr><a href=\"http://eclipse.org/jetty\">Powered by Jetty://9.4.27.v20200227</a><hr/>\n\n</body>\n</html>\n", "content_length": "527", "content_type": "text/html;charset=iso-8859-1", "elapsed": 1, "msg": "Status code was 400 and not [302]: HTTP Error 400: Bad Request", "redirected": false, "server":"Jetty(9.4.27.v20200227)", "status": 400, "url":"http://192.168.0.120:9080/credentials/store/system/domain/_/createCredentials", "x_content_type_options": "nosniff"}