blob: 69deb37560095c533f5bc96483032ca7462b2117 [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
log = logging.getLogger(__name__)
def _elements_equal(e1, e2):
if e1.tag != e2.tag:
return False
if e1.text != e2.text:
return False
if e1.tail != e2.tail:
return False
if e1.attrib != e2.attrib:
return False
if len(e1) != len(e2):
return False
return all(_elements_equal(c1, c2) for c1, c2 in zip(e1, e2))
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:
_job_exists = __salt__['jenkins.job_exists'](name)
if _job_exists:
_current_job_config = __salt__['jenkins.get_job_config'](name)
buf = six.moves.StringIO(_current_job_config)
oldXML = ET.fromstring(buf.read())
cached_source_path = __salt__['cp.cache_file'](config, __env__)
with salt.utils.fopen(cached_source_path) as _fp:
newXML = ET.fromstring(_fp.read())
if not _elements_equal(oldXML, newXML):
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