blob: 493aebe65c59d121a67a1b25bc4405e0a83ca019 [file] [log] [blame]
Jakub Josef8e7385e2016-12-07 21:20:34 +01001import bcrypt
2import logging
3import requests
4from salt.exceptions import SaltInvocationError
5
6logger = logging.getLogger(__name__)
7
8
Jakub Josef7ae6b242016-12-14 14:41:44 +01009def call_groovy_script(script, props, username=None, password=None, success_status_codes=[200]):
Jakub Josef8e7385e2016-12-07 21:20:34 +010010 """
11 Common method for call Jenkins groovy script API
12
Jakub Josef7ae6b242016-12-14 14:41:44 +010013 :param script: groovy script template
14 :param props: groovy script properties
15 :param username: jenkins username (optional,
16 if missing creds from sall will be used)
17 :param password: jenkins password (optional,
18 if missing creds from sall will be used)
19 :param success_status_codes: success response status code
20 (optional) in some cases we want to declare error call as success
Jakub Josef8e7385e2016-12-07 21:20:34 +010021 :returns: HTTP dict {status,code,msg}
22 """
23 ret = {
24 "status": "FAILED",
25 "code": 999,
26 "msg": ""
27 }
28 jenkins_url, jenkins_user, jenkins_password = get_jenkins_auth()
Jakub Josef7ae6b242016-12-14 14:41:44 +010029 if username:
30 jenkins_user = username
31 if password:
32 jenkins_password = password
33
Jakub Josef8e7385e2016-12-07 21:20:34 +010034 if not jenkins_url:
35 raise SaltInvocationError('No Jenkins URL found.')
Jakub Josefe13e2e72016-12-08 13:41:19 +010036
37 token_obj = get_api_crumb(jenkins_url, jenkins_user, jenkins_password)
38 req_data = {"script": render_groovy_script(script, props)}
39 if token_obj:
40 req_data[token_obj["crumbRequestField"]] = token_obj["crumb"]
41
42 logger.debug("Calling Jenkins script API with URL: %s", jenkins_url)
43 req = requests.post('%s/scriptText' % jenkins_url,
44 auth=(jenkins_user, jenkins_password),
45 data=req_data)
46 ret["code"] = req.status_code
Jakub Josef7ae6b242016-12-14 14:41:44 +010047 if req.status_code in success_status_codes:
Jakub Josefe13e2e72016-12-08 13:41:19 +010048 ret["status"] = "SUCCESS"
49 ret["msg"] = req.text
50 logger.debug("Jenkins script API call success: %s", ret)
Jakub Josef8e7385e2016-12-07 21:20:34 +010051 else:
Jakub Josefe13e2e72016-12-08 13:41:19 +010052 logger.error("Jenkins script API call failed. \
53 Return code %s. Text: %s", req.status_code, req.text)
Jakub Josef8e7385e2016-12-07 21:20:34 +010054 return ret
55
56
57def render_groovy_script(script, props):
58 """
59 Helper method for rendering groovy script with props
60
Jakub Josef3de91af2016-12-08 17:03:33 +010061 :param script: groovy script template
62 :param props: groovy script properties
Jakub Josef8e7385e2016-12-07 21:20:34 +010063 :returns: generated groovy script
64 """
65 return script.format(**props)
66
67
68def get_api_crumb(jenkins_url=None, jenkins_user=None, jenkins_password=None):
69 """
70 Obtains Jenkins API crumb, if CSRF protection is enabled.
71 Jenkins params can be given by params or not, if not,
72 params will be get from salt.
73
74 :param jenkins_url: Jenkins URL (optional)
75 :param jenkins_user: Jenkins admin username (optional)
76 :param jenkins_password: Jenkins admin password (optional)
77 :returns: salt-specified state dict
78 """
79 if not jenkins_url:
80 jenkins_url, jenkins_user, jenkins_password = get_jenkins_auth()
81 logger.debug("Obtaining Jenkins API crumb for URL: %s", jenkins_url)
82 tokenReq = requests.get("%s/crumbIssuer/api/json" % jenkins_url,
Jakub Josefe13e2e72016-12-08 13:41:19 +010083 auth=(jenkins_user, jenkins_password) if jenkins_user else None)
Jakub Josef8e7385e2016-12-07 21:20:34 +010084 if tokenReq.status_code == 200:
85 return tokenReq.json()
Jakub Josef7ae6b242016-12-14 14:41:44 +010086 elif tokenReq.status_code in [404, 401]:
87 # 404 means CSRF security is disabled, so api crumb is not necessary,
88 # 401 means unauthorized
Jakub Josefe13e2e72016-12-08 13:41:19 +010089 return None
Jakub Josef8e7385e2016-12-07 21:20:34 +010090 else:
Jakub Josefe13e2e72016-12-08 13:41:19 +010091 raise Exception("Cannot obtain Jenkins API crumb. Status code: %s. Text: %s" %
Jakub Josef3de91af2016-12-08 17:03:33 +010092 (tokenReq.status_code, tokenReq.text))
Jakub Josef8e7385e2016-12-07 21:20:34 +010093
94
Jakub Josef8e7385e2016-12-07 21:20:34 +010095def get_jenkins_auth():
96 """
97 Get jenkins params from salt
98 """
99 jenkins_url = __salt__['config.get']('jenkins.url') or \
100 __salt__['config.get']('jenkins:url') or \
101 __salt__['pillar.get']('jenkins.url')
102
103 jenkins_user = __salt__['config.get']('jenkins.user') or \
104 __salt__['config.get']('jenkins:user') or \
105 __salt__['pillar.get']('jenkins.user')
106
107 jenkins_password = __salt__['config.get']('jenkins.password') or \
108 __salt__['config.get']('jenkins:password') or \
109 __salt__['pillar.get']('jenkins.password')
110
111 return (jenkins_url, jenkins_user, jenkins_password)
112
113
114def encode_password(password):
115 """
116 Hash plaintext password by jenkins bcrypt algorithm
117 :param password: plain-text password
118 :returns: bcrypt hashed password
119 """
120 if isinstance(password, str):
121 return bcrypt.hashpw(password, bcrypt.gensalt(prefix=b"2a"))