blob: e93bcbb3c501a5ee85a34b12490e392f4c97e0c3 [file] [log] [blame]
# -*- coding: utf-8 -*-
# Import Python libs
from __future__ import absolute_import
import difflib
import logging
# Import Salt libs
import salt.ext.six as six
import salt.utils
# Import XML parser
import xml.etree.ElementTree as ET
import hashlib
# Jenkins
try:
import jenkins
HAS_JENKINS = True
except ImportError:
HAS_JENKINS = False
log = logging.getLogger(__name__)
def __virtual__():
'''
Only load if jenkins_common module exist.
'''
if not HAS_JENKINS:
return (
False,
'The jenkins_job state module cannot be loaded: '
'python Jenkins API client could not be imported')
if 'jenkins_common.call_groovy_script' not in __salt__:
return (
False,
'The jenkins_job state module cannot be loaded: '
'jenkins_common not found')
return True
def _elements_equal(e1, e2):
return hashlib.md5(e1).hexdigest() == hashlib.md5(e2).hexdigest()
def present(name,
config=None,
**kwargs):
'''
Ensure the job is present in the Jenkins
configured jobs
name
The unique name for the Jenkins job
config
The Salt URL for the file to use for
configuring the job.
'''
test = __opts__['test']
ret = {'name': name,
'result': True,
'changes': {},
'comment': ['Job {0} is up to date.'.format(name)]}
if test:
status = 'CREATED'
ret['changes'][name] = status
ret['comment'] = 'Job %s %s' % (name, status.lower())
else:
_current_job_config = ''
_job_exists = True
try:
_current_job_config = __salt__['jenkins.get_job_config'](name)
except Exception as e:
if 'does not exist' in str(e):
_job_exists = False
else:
raise e
if _job_exists:
buf = six.moves.StringIO(_current_job_config)
oldXMLstring = buf.read()
cached_source_path = __salt__['cp.cache_file'](config, __env__)
with salt.utils.fopen(cached_source_path) as _fp:
newXMLstring = _fp.read()
if not _elements_equal(oldXMLstring.strip(), newXMLstring.strip()):
oldXML = ET.fromstring(oldXMLstring)
newXML = ET.fromstring(newXMLstring)
diff = difflib.unified_diff(
ET.tostringlist(oldXML, encoding='utf8', method='xml'),
ET.tostringlist(newXML, encoding='utf8', method='xml'), lineterm='')
__salt__['jenkins.update_job'](name, config, __env__)
ret['changes'][name] = ''.join(diff)
ret['comment'].append('Job {0} updated.'.format(name))
else:
cached_source_path = __salt__['cp.cache_file'](config, __env__)
with salt.utils.fopen(cached_source_path) as _fp:
new_config_xml = _fp.read()
__salt__['jenkins.create_job'](name, config, __env__)
buf = six.moves.StringIO(new_config_xml)
diff = difflib.unified_diff('', buf.readlines(), lineterm='')
ret['changes'][name] = ''.join(diff)
ret['comment'].append('Job {0} added.'.format(name))
ret['comment'] = '\n'.join(ret['comment'])
return ret
def absent(name,
**kwargs):
'''
Ensure the job is present in the Jenkins
configured jobs
name
The name of the Jenkins job to remove.
'''
test = __opts__['test']
ret = {'name': name,
'result': True,
'changes': {},
'comment': []}
if test:
status = 'DELETED'
ret['changes'][name] = status
ret['comment'] = 'Node %s %s' % (name, status.lower())
else:
_job_exists = __salt__['jenkins.job_exists'](name)
if _job_exists:
__salt__['jenkins.delete_job'](name)
ret['comment'] = 'Job {0} deleted.'.format(name)
else:
ret['comment'] = 'Job {0} already absent.'.format(name)
return ret
def cleanup(name, jobs, **kwargs):
'''
Perform a cleanup - uninstall any installed job absents in given jobs list
name
The name of the Jenkins job to remove.
jobs
List of jobs which may NOT be uninstalled
'''
test = __opts__['test']
ret = {'name': name,
'result': True,
'changes': {},
'comment': "Cleanup not necessary"}
list_jobs_groovy = """\
print(Jenkins.instance.items.collect{it -> it.name})
"""
deleted_jobs = []
if test:
status = 'CLEANED'
ret['changes'][name] = status
ret['comment'] = 'Jobs %s' % status.lower()
else:
call_result = __salt__['jenkins_common.call_groovy_script'](
list_jobs_groovy, {})
if call_result["code"] == 200:
existing_jobs = call_result["msg"]
if existing_jobs:
for job in existing_jobs[1:-1].split(","):
if job:
job = job.strip()
if job not in jobs:
__salt__['jenkins.delete_job'](job)
deleted_jobs.append(job)
else:
log.error("Cannot get existing jobs list from Jenkins")
if len(deleted_jobs) > 0:
for del_job in deleted_jobs:
ret['changes'][del_job] = "removed"
ret['comment'] = 'Jobs {} deleted.'.format(deleted_jobs)
else:
status = 'FAILED'
log.error(
"Jenkins jobs API call failure: %s", call_result["msg"])
ret['comment'] = 'Jenkins jobs API call failure: %s' % (
call_result["msg"])
return ret