blob: a8ee964e69c7bac94a2f1bc542c16e7dee203d1a [file] [log] [blame]
Jakub Josefe3807982016-12-15 11:54:51 +01001# -*- coding: utf-8 -*-
2
3# Import Python libs
4from __future__ import absolute_import
5import difflib
6import logging
7
8# Import Salt libs
9import salt.ext.six as six
10import salt.utils
11
12# Import XML parser
13import xml.etree.ElementTree as ET
14
15log = logging.getLogger(__name__)
16
17
18def _elements_equal(e1, e2):
19 if e1.tag != e2.tag:
20 return False
21 if e1.text != e2.text:
22 return False
23 if e1.tail != e2.tail:
24 return False
25 if e1.attrib != e2.attrib:
26 return False
27 if len(e1) != len(e2):
28 return False
29 return all(_elements_equal(c1, c2) for c1, c2 in zip(e1, e2))
30
31
32def present(name,
33 config=None,
34 **kwargs):
35 '''
36 Ensure the job is present in the Jenkins
37 configured jobs
38 name
39 The unique name for the Jenkins job
40 config
41 The Salt URL for the file to use for
42 configuring the job.
43 '''
Jakub Josef2a7739b2017-01-24 18:33:44 +010044 test = __opts__['test']
Jakub Josefe3807982016-12-15 11:54:51 +010045 ret = {'name': name,
46 'result': True,
47 'changes': {},
48 'comment': ['Job {0} is up to date.'.format(name)]}
Jakub Josef2a7739b2017-01-24 18:33:44 +010049 if test:
50 status = 'CREATED'
51 ret['changes'][name] = status
52 ret['comment'] = 'Job %s %s' % (name, status.lower())
Jakub Josefe3807982016-12-15 11:54:51 +010053 else:
Jakub Josef2a7739b2017-01-24 18:33:44 +010054 _job_exists = __salt__['jenkins.job_exists'](name)
55 if _job_exists:
56 _current_job_config = __salt__['jenkins.get_job_config'](name)
57 buf = six.moves.StringIO(_current_job_config)
58 oldXML = ET.fromstring(buf.read())
Jakub Josefe3807982016-12-15 11:54:51 +010059
Jakub Josef2a7739b2017-01-24 18:33:44 +010060 cached_source_path = __salt__['cp.cache_file'](config, __env__)
61 with salt.utils.fopen(cached_source_path) as _fp:
62 newXML = ET.fromstring(_fp.read())
63 if not _elements_equal(oldXML, newXML):
64 diff = difflib.unified_diff(
65 ET.tostringlist(oldXML, encoding='utf8', method='xml'),
66 ET.tostringlist(newXML, encoding='utf8', method='xml'), lineterm='')
67 __salt__['jenkins.update_job'](name, config, __env__)
68 ret['changes'] = ''.join(diff)
69 ret['comment'].append('Job {0} updated.'.format(name))
Jakub Josefe3807982016-12-15 11:54:51 +010070
Jakub Josef2a7739b2017-01-24 18:33:44 +010071 else:
72 cached_source_path = __salt__['cp.cache_file'](config, __env__)
73 with salt.utils.fopen(cached_source_path) as _fp:
74 new_config_xml = _fp.read()
Jakub Josefe3807982016-12-15 11:54:51 +010075
Jakub Josef2a7739b2017-01-24 18:33:44 +010076 __salt__['jenkins.create_job'](name, config, __env__)
Jakub Josefe3807982016-12-15 11:54:51 +010077
Jakub Josef2a7739b2017-01-24 18:33:44 +010078 buf = six.moves.StringIO(new_config_xml)
79 _current_job_config = buf.readlines()
80
81 diff = difflib.unified_diff('', buf, lineterm='')
82 ret['changes'] = ''.join(diff)
83 ret['comment'].append('Job {0} added.'.format(name))
84
85 ret['comment'] = '\n'.join(ret['comment'])
Jakub Josefe3807982016-12-15 11:54:51 +010086 return ret
87
88
89def absent(name,
90 **kwargs):
91 '''
92 Ensure the job is present in the Jenkins
93 configured jobs
94
95 name
96 The name of the Jenkins job to remove.
97
98 '''
Jakub Josef2a7739b2017-01-24 18:33:44 +010099 test = __opts__['test']
Jakub Josefe3807982016-12-15 11:54:51 +0100100 ret = {'name': name,
101 'result': True,
102 'changes': {},
103 'comment': []}
Jakub Josef2a7739b2017-01-24 18:33:44 +0100104 if test:
105 status = 'DELETED'
106 ret['changes'][name] = status
107 ret['comment'] = 'Node %s %s' % (name, status.lower())
Jakub Josefe3807982016-12-15 11:54:51 +0100108 else:
Jakub Josef2a7739b2017-01-24 18:33:44 +0100109 _job_exists = __salt__['jenkins.job_exists'](name)
110
111 if _job_exists:
112 __salt__['jenkins.delete_job'](name)
113 ret['comment'] = 'Job {0} deleted.'.format(name)
114 else:
115 ret['comment'] = 'Job {0} already absent.'.format(name)
116 return ret
117
118
119def cleanup(name, jobs, **kwargs):
120 '''
121 Perform a cleanup - uninstall any installed job absents in given jobs list
122
123 name
124 The name of the Jenkins job to remove.
125 jobs
126 List of jobs which may NOT be uninstalled
127
128 '''
129 test = __opts__['test']
130 ret = {'name': name,
131 'result': True,
132 'changes': {},
133 'comment': "Cleanup not necessary"}
134 list_jobs_groovy = """\
135 print(Jenkins.instance.items.collect{{it -> it.name}})
136 """
137 deleted_jobs = []
138 if test:
139 status = 'CLEANED'
140 ret['changes'][name] = status
141 ret['comment'] = 'Jobs %s' % status.lower()
142 else:
143 call_result = __salt__['jenkins_common.call_groovy_script'](list_jobs_groovy,{})
144 if call_result["code"] == 200:
145 existing_jobs = call_result["msg"]
146 if existing_jobs:
147 for job in existing_jobs[1:-1].split(","):
148 if job:
149 job = job.strip()
150 if job not in jobs:
151 __salt__['jenkins.delete_job'](job)
152 deleted_jobs.append(job)
153 else:
154 log.error("Cannot get existing jobs list from Jenkins")
155 if len(deleted_jobs) > 0:
156 for del_job in deleted_jobs:
157 ret['changes'][del_job] = "removed"
158 ret['comment'] = 'Jobs {} deleted.'.format(deleted_jobs)
159 else:
160 status = 'FAILED'
161 log.error(
162 "Jenkins jobs API call failure: %s", call_result["msg"])
163 ret['comment'] = 'Jenkins jobs API call failure: %s' % (
164 call_result["msg"])
Jakub Josefe3807982016-12-15 11:54:51 +0100165 return ret