blob: 50ed64d965613f79e0ba80d4f0be38a5852fd100 [file] [log] [blame]
import bcrypt
import logging
import requests
from salt.exceptions import SaltInvocationError
logger = logging.getLogger(__name__)
def call_groovy_script(script, props, username=None, password=None, success_status_codes=[200]):
"""
Common method for call Jenkins groovy script API
:param script: groovy script template
:param props: groovy script properties
:param username: jenkins username (optional,
if missing creds from sall will be used)
:param password: jenkins password (optional,
if missing creds from sall will be used)
:param success_status_codes: success response status code
(optional) in some cases we want to declare error call as success
:returns: HTTP dict {status,code,msg}
"""
ret = {
"status": "FAILED",
"code": 999,
"msg": ""
}
jenkins_url, jenkins_user, jenkins_password = get_jenkins_auth()
if username:
jenkins_user = username
if password:
jenkins_password = password
if not jenkins_url:
raise SaltInvocationError('No Jenkins URL found.')
token_obj = get_api_crumb(jenkins_url, jenkins_user, jenkins_password)
req_data = {"script": render_groovy_script(script, props)}
if token_obj:
req_data[token_obj["crumbRequestField"]] = token_obj["crumb"]
logger.debug("Calling Jenkins script API with URL: %s", jenkins_url)
req = requests.post('%s/scriptText' % jenkins_url,
auth=(jenkins_user, jenkins_password),
data=req_data)
ret["code"] = req.status_code
ret["msg"] = req.text
if req.status_code in success_status_codes:
ret["status"] = "SUCCESS"
logger.debug("Jenkins script API call success: %s", ret)
else:
logger.error("Jenkins script API call failed. \
Return code %s. Text: %s", req.status_code, req.text)
return ret
def render_groovy_script(script, props):
"""
Helper method for rendering groovy script with props
:param script: groovy script template
:param props: groovy script properties
:returns: generated groovy script
"""
return script.format(**props)
def get_api_crumb(jenkins_url=None, jenkins_user=None, jenkins_password=None):
"""
Obtains Jenkins API crumb, if CSRF protection is enabled.
Jenkins params can be given by params or not, if not,
params will be get from salt.
:param jenkins_url: Jenkins URL (optional)
:param jenkins_user: Jenkins admin username (optional)
:param jenkins_password: Jenkins admin password (optional)
:returns: salt-specified state dict
"""
if not jenkins_url:
jenkins_url, jenkins_user, jenkins_password = get_jenkins_auth()
logger.debug("Obtaining Jenkins API crumb for URL: %s", jenkins_url)
tokenReq = requests.get("%s/crumbIssuer/api/json" % jenkins_url,
auth=(jenkins_user, jenkins_password) if jenkins_user else None)
if tokenReq.status_code == 200:
return tokenReq.json()
elif tokenReq.status_code in [404, 401]:
# 404 means CSRF security is disabled, so api crumb is not necessary,
# 401 means unauthorized
return None
else:
raise Exception("Cannot obtain Jenkins API crumb. Status code: %s. Text: %s" %
(tokenReq.status_code, tokenReq.text))
def get_jenkins_auth():
"""
Get jenkins params from salt
"""
jenkins_url = __salt__['config.get']('jenkins.url') or \
__salt__['config.get']('jenkins:url') or \
__salt__['pillar.get']('jenkins.url')
jenkins_user = __salt__['config.get']('jenkins.user') or \
__salt__['config.get']('jenkins:user') or \
__salt__['pillar.get']('jenkins.user')
jenkins_password = __salt__['config.get']('jenkins.password') or \
__salt__['config.get']('jenkins:password') or \
__salt__['pillar.get']('jenkins.password')
return (jenkins_url, jenkins_user, jenkins_password)
def encode_password(password):
"""
Hash plaintext password by jenkins bcrypt algorithm
:param password: plain-text password
:returns: bcrypt hashed password
"""
if isinstance(password, str):
return bcrypt.hashpw(password, bcrypt.gensalt(prefix=b"2a"))