Commit e17e20eee0cae1d2766afeb8953ad43c893ad4af
1 parent
e6a2bdcb60
Exists in
master
and in
1 other branch
first stage playbook
Showing
52 changed files
with
1254 additions
and
0 deletions
Show diff stats
README.md
... | ... | @@ -0,0 +1,22 @@ |
1 | +#Alfresco benchmark playbook | |
2 | + | |
3 | +This ansible playbook allows one to easily deploy an Alfresco benchmark infrastructure on multiple servers. | |
4 | + | |
5 | +##Requirements | |
6 | + | |
7 | +The playbook has been written and tested with Ansible 2.2. Some additionnal modules have been added to the playbook: | |
8 | + | |
9 | + * ansible-xml by cmprescott (requires python-lxml on remote end) | |
10 | + * selenium | |
11 | + | |
12 | +At the moment the target hosts need to have direct acces to internet as we are using public repos. | |
13 | + | |
14 | +##How to use: | |
15 | + | |
16 | +Edit the _inventory_ file and add your hosts to the appropriate section. If you don't understand the roles of each server, you should probably start reading [Derek Huley's documentation](https://github.com/AlfrescoBenchmark/alfresco-benchmark/tree/master/docs) about the [Alfresco benchmark framework](https://github.com/AlfrescoBenchmark). | |
17 | + | |
18 | +##TODO | |
19 | + | |
20 | + * Make it possible to download software from the Ansible machine instead of target machine (in case target cannot access internet). | |
21 | + * Allow Oracle JDK usage | |
22 | + * RedHat like environments | ... | ... |
alfbm.retry
... | ... | @@ -0,0 +1 @@ |
1 | +alfbmsrv | ... | ... |
alfbm.yml
config.yml
... | ... | @@ -0,0 +1,48 @@ |
1 | +artifact_repo: https://nexus.alfresco.com/nexus/service/local/repositories/snapshots/content | |
2 | + | |
3 | +bm_server_path: /org/alfresco/alfresco-benchmark-server/2.2.0-SNAPSHOT/alfresco-benchmark-server-2.2.0-20170403.100924-4.war | |
4 | +bm_sample: /org/alfresco/alfresco-benchmark-sample/2.2.0-SNAPSHOT/alfresco-benchmark-sample-2.2.0-20170403.101041-4.war | |
5 | +tests_signup_path: /org/alfresco/alfresco-benchmark-tests-ent-signup/2.5-SNAPSHOT/alfresco-benchmark-tests-ent-signup-2.5-20170306.103110-4.war | |
6 | +tests_cmis_path: /org/alfresco/alfresco-benchmark-tests-cmis/1.7-SNAPSHOT/alfresco-benchmark-tests-cmis-1.7-20160818.133550-1.war | |
7 | +tests_dataload_path: /org/alfresco/alfresco-benchmark-tests-dataload/2.8-SNAPSHOT/alfresco-benchmark-tests-dataload-2.8-20170306.105256-3.war | |
8 | +tests_share_path: /org/alfresco/alfresco-benchmark-tests-share/5.2.0-SNAPSHOT/alfresco-benchmark-tests-share-5.2.0-20170306.102441-46.war | |
9 | +tests_workflow_path: /org/alfresco/alfresco-benchmark-tests-workflow/1.3-SNAPSHOT/alfresco-benchmark-tests-workflow-1.3-20170403.102028-12.war | |
10 | +tests_desktopsync_path: /org/alfresco/alfresco-benchmark-tests-desktop-sync/1.3-SNAPSHOT/alfresco-benchmark-tests-desktop-sync-1.3-20160615.142236-21.war | |
11 | + | |
12 | +# Use either Java 7 or 8 | |
13 | +#java_ver: 8 | |
14 | + | |
15 | +# Set java flavor (only openjdk for now) | |
16 | +#java_flav: openjdk | |
17 | + | |
18 | +# Use either Tomcat 7 or 8 | |
19 | +#tomcat_ver: 8 | |
20 | + | |
21 | +# Set port for Tomcat to listen on. Set "tomcat_port" in host_vars to specify different ports on each host | |
22 | +#tomcat_prt: 9080 | |
23 | + | |
24 | +# Should we remove existing war files | |
25 | +#tomcat_cln: False | |
26 | + | |
27 | +# Selenium version MUST be X.Y.Z | |
28 | +#selenium_ver: 3.3.1 | |
29 | + | |
30 | +# Specify a host to endorse the role of a Selenium Hub. defaults to the first bm-server (there should be only one) | |
31 | +#selenium_hub_port: 4444 | |
32 | +# DO NOT EDIT FURTHER. | |
33 | +# Thereafter we only set defaults | |
34 | + | |
35 | +java_version: "{{ java_ver | default(8) }}" | |
36 | +java_flavor: "{{ java_flav | default('openjdk') }}" | |
37 | +tomcat_version: "{{ tomcat_ver | default(7) }}" | |
38 | +tomcat_clean: "{{ย tomcat_cln | default(False) }}" | |
39 | +tomcat_port: "{{ tomcat_prt | default(8080) }}" | |
40 | + | |
41 | +selenium_version: "{{ selenium_ver | default('3.3.1') }}" | |
42 | +selenium_release: "{{ selenium_version | regex_replace('\\.\\d+$','') }}" | |
43 | +selenium_url: "http://selenium-release.storage.googleapis.com/{{ selenium_release }}/selenium-server-standalone-{{ selenium_version }}.jar" | |
44 | + | |
45 | +selenium_hub_portnumber: "{{ selenium_hub_port | default(4444) }}" | |
46 | + | |
47 | +mongodb_version: "{{ mongodb_ver | default('3.4') }}" | |
48 | + | ... | ... |
inventory
library/xml
... | ... | @@ -0,0 +1,638 @@ |
1 | +#!/usr/bin/python | |
2 | +# -*- coding: utf-8 -*- | |
3 | +# | |
4 | +# xml - Manage bits and pieces of XML files | |
5 | +# | |
6 | +# Copyright 2014, Red Hat, Inc. | |
7 | +# Tim Bielawa <tbielawa@redhat.com> | |
8 | +# Magnus Hedemark <mhedemar@redhat.com> | |
9 | +# | |
10 | +# This software may be freely redistributed under the terms of the GNU | |
11 | +# general public license version 2. | |
12 | +# | |
13 | +# You should have received a copy of the GNU General Public License | |
14 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | + | |
16 | + | |
17 | +DOCUMENTATION = ''' | |
18 | +--- | |
19 | +module: xml | |
20 | +short_description: Manage bits and pieces of XML files or strings | |
21 | +description: | |
22 | + - A CRUD-like interface to managing bits of XML files. You might also be interested in a brief tutorial, U(http://www.w3schools.com/xpath/). Note that module this does not handle complicated xpath expressions. So limit xpath selectors to simple expressions. | |
23 | +version_added: "1.0" | |
24 | +options: | |
25 | + path: | |
26 | + description: | |
27 | + - Path to the file to operate on. File must exist ahead of time. | |
28 | + required: true unless xmlstring is given | |
29 | + default: null | |
30 | + choices: [] | |
31 | + aliases: ['dest', 'file'] | |
32 | + xmlstring: | |
33 | + description: | |
34 | + - A string containing XML on which to operate. | |
35 | + required: true unless file is given | |
36 | + default: null | |
37 | + choices: [] | |
38 | + xpath: | |
39 | + description: | |
40 | + - A valid XPath expression describing the item(s) you want to manipulate. Operates on the document root, C(/), by default. | |
41 | + required: false | |
42 | + default: / | |
43 | + choices: [] | |
44 | + namespaces: | |
45 | + description: | |
46 | + - The namespace prefix:uri mapping for the XPath expression. Needs to be a *map*, not a list of items. | |
47 | + required: false | |
48 | + default: null | |
49 | + choices: [] | |
50 | + ensure: | |
51 | + description: | |
52 | + - Set or remove an xpath selection (node(s), attribute(s)) | |
53 | + required: false | |
54 | + default: present | |
55 | + choices: | |
56 | + - "absent" | |
57 | + - "present" | |
58 | + value: | |
59 | + description: | |
60 | + - Desired state of the selected attribute. Either a string, or to unset a value, the Python C(None) keyword (YAML Equivalent, C(null)). | |
61 | + required: false | |
62 | + default: Elements default to no value (but present). Attributes default to an empty string. | |
63 | + choices: [] | |
64 | + add_children: | |
65 | + description: | |
66 | + - 'Add additional child-element(s) to a selected element. Child elements must be given in a list and each item may be either a string (ex: C(children=ansible) to add an empty C(<ansible/>) child element), or a hash where the key is an element name and the value is the element value.' | |
67 | + required: false | |
68 | + default: null | |
69 | + choices: [] | |
70 | + set_children: | |
71 | + description: | |
72 | + - 'Set the the child-element(s) of a selected element. Removes any existing children. Child elements must be specified as in C(add_children).' | |
73 | + required: false | |
74 | + default: null | |
75 | + choices: [] | |
76 | + count: | |
77 | + description: | |
78 | + - "Search for a given C(xpath) and provide the count of any matches" | |
79 | + required: false | |
80 | + default: null | |
81 | + choices: [] | |
82 | + print_match: | |
83 | + description: | |
84 | + - "Search for a given C(xpath) and print out any matches" | |
85 | + required: false | |
86 | + default: null | |
87 | + choices: [] | |
88 | + pretty_print: | |
89 | + description: | |
90 | + - "Pretty print output XML" | |
91 | + required: false | |
92 | + default: false | |
93 | + choices: [] | |
94 | + content: | |
95 | + description: | |
96 | + - "Search for a given C(xpath) and get content" | |
97 | + required: false | |
98 | + default: false | |
99 | + choices: | |
100 | + - "attribute" | |
101 | + - "text" | |
102 | + input_type: | |
103 | + description: | |
104 | + - "Type of input for add_children and set_children" | |
105 | + required: false | |
106 | + default: "yaml" | |
107 | + choices: | |
108 | + - "yaml" | |
109 | + - "xml" | |
110 | +requirements: | |
111 | + - The remote end must have the Python C(lxml) library installed | |
112 | +author: Tim Bielawa, Magnus Hedemark | |
113 | +''' | |
114 | + | |
115 | + | |
116 | +from io import BytesIO | |
117 | +from lxml import etree | |
118 | +try: | |
119 | + import json | |
120 | +except: | |
121 | + import simplejson as json | |
122 | +import lxml | |
123 | +import sys, os, re, traceback | |
124 | + | |
125 | +def print_match(module, tree, xpath, namespaces): | |
126 | + match = tree.xpath(xpath, namespaces=namespaces) | |
127 | + match_xpaths = [] | |
128 | + for m in match: | |
129 | + match_xpaths.append(tree.getpath(m)) | |
130 | + match_str = json.dumps(match_xpaths) | |
131 | + msg = "selector '%s' match: %s" % (xpath, match_str) | |
132 | + finish(module, tree, xpath, namespaces, changed=False, msg=msg) | |
133 | + | |
134 | +def count(module, tree, xpath, namespaces): | |
135 | + """ Return the count of nodes matching the xpath """ | |
136 | + hits = tree.xpath("count(/%s)" % xpath, namespaces=namespaces) | |
137 | + finish(module, tree, xpath, namespaces, changed=False, msg=int(hits), hitcount=int(hits)) | |
138 | + | |
139 | +def is_node(tree, xpath, namespaces): | |
140 | + """ Test if a given xpath matches anything and if that match is a node. | |
141 | + | |
142 | + For now we just assume you're only searching for one specific thing.""" | |
143 | + if xpath_matches(tree, xpath, namespaces): | |
144 | + # OK, it found something | |
145 | + match = tree.xpath(xpath, namespaces=namespaces) | |
146 | + if type(match[0]) == lxml.etree._Element: | |
147 | + return True | |
148 | + | |
149 | + return False | |
150 | + | |
151 | +def is_attribute(tree, xpath, namespaces): | |
152 | + """ Test if a given xpath matches and that match is an attribute | |
153 | + | |
154 | +An xpath attribute search will only match one item""" | |
155 | + if xpath_matches(tree, xpath, namespaces): | |
156 | + match = tree.xpath(xpath, namespaces=namespaces) | |
157 | + if type(match[0]) == lxml.etree._ElementStringResult: | |
158 | + return True | |
159 | + return False | |
160 | + | |
161 | +def xpath_matches(tree, xpath, namespaces): | |
162 | + """ Test if a node exists """ | |
163 | + if tree.xpath(xpath, namespaces=namespaces): | |
164 | + return True | |
165 | + else: | |
166 | + return False | |
167 | + | |
168 | +def delete_xpath_target(module, tree, xpath, namespaces): | |
169 | + """ Delete an attribute or element from a tree """ | |
170 | + try: | |
171 | + for result in tree.xpath(xpath, namespaces=namespaces): | |
172 | + if not module.check_mode: | |
173 | + # Get the xpath for this result | |
174 | + if is_attribute(tree, xpath, namespaces): | |
175 | + # Delete an attribute | |
176 | + parent = result.getparent() | |
177 | + # Pop this attribute match out of the parent | |
178 | + # node's 'attrib' dict by using this match's | |
179 | + # 'attrname' attribute for the key | |
180 | + parent.attrib.pop(result.attrname) | |
181 | + elif is_node(tree, xpath, namespaces): | |
182 | + # Delete an element | |
183 | + result.getparent().remove(result) | |
184 | + except Exception, e: | |
185 | + abort(module, "Couldn't delete xpath target: %s (%s)" % (xpath, str(e))) | |
186 | + else: | |
187 | + finish(module, tree, xpath, namespaces, changed=True) | |
188 | + | |
189 | +def set_target_children_inner(module, tree, xpath, namespaces, children, type): | |
190 | + matches = tree.xpath(xpath, namespaces=namespaces) | |
191 | + | |
192 | + # Create a list of our new children | |
193 | + children = children_to_nodes(module, children, type) | |
194 | + children_as_string = [lxml.etree.tostring(c) for c in children] | |
195 | + | |
196 | + changed = False | |
197 | + | |
198 | + def replace_children_of(match): | |
199 | + if not module.check_mode: | |
200 | + for element in match.getchildren(): | |
201 | + match.remove(element) | |
202 | + match.extend(children) | |
203 | + | |
204 | + # xpaths always return matches as a list, so.... | |
205 | + for match in matches: | |
206 | + # Check if elements differ | |
207 | + if len(match.getchildren()) == len(children): | |
208 | + for idx, element in enumerate(match.getchildren()): | |
209 | + if lxml.etree.tostring(element) != children_as_string[idx]: | |
210 | + replace_children_of(match) | |
211 | + changed = True | |
212 | + break | |
213 | + else: | |
214 | + replace_children_of(match) | |
215 | + changed = True | |
216 | + | |
217 | + return changed | |
218 | + | |
219 | +def set_target_children(module, tree, xpath, namespaces, children, type): | |
220 | + changed = set_target_children_inner(module, tree, xpath, namespaces, children, type) | |
221 | + # Write it out | |
222 | + finish(module, tree, xpath, namespaces, changed=changed) | |
223 | + | |
224 | +def add_target_children(module, tree, xpath, namespaces, children, type): | |
225 | + if is_node(tree, xpath, namespaces): | |
226 | + new_kids = children_to_nodes(module, children, type) | |
227 | + for node in tree.xpath(xpath, namespaces=namespaces): | |
228 | + if not module.check_mode: node.extend(new_kids) | |
229 | + finish(module, tree, xpath, namespaces, changed=True) | |
230 | + else: | |
231 | + finish(module, tree, xpath, namespaces) | |
232 | + | |
233 | +_ident = "[a-zA-Z-][a-zA-Z0-9_-]*" | |
234 | +_nsIdent = _ident +"|"+_ident+":"+_ident | |
235 | +_xpstr = "('(?:.*)'|\"(?:.*)\")" # Note: we can't reasonably support the 'if you need to put both ' and " in a string, concatenate | |
236 | + # strings wrapped by the other delimiter' XPath trick, especially as simple XPath. | |
237 | + | |
238 | +_re_splitSimpleLast = re.compile("^(.*)/("+_nsIdent+")$") | |
239 | +_re_splitSimpleLastEqValue = re.compile("^(.*)/("+_nsIdent+")/text\\(\\)="+_xpstr+"$") | |
240 | +_re_splitSimpleAttrLast = re.compile("^(.*)/(@(?:"+_nsIdent+"))$") | |
241 | +_re_splitSimpleAttrLastEqValue = re.compile("^(.*)/(@(?:"+_nsIdent+"))="+_xpstr+"$") | |
242 | + | |
243 | +_re_splitSubLast = re.compile("^(.*)/("+_nsIdent+")\\[(.*)\\]$") | |
244 | + | |
245 | +_re_splitOnlyEqValue = re.compile("^(.*)/text\\(\\)="+_xpstr+"$") | |
246 | + | |
247 | +def _extract_xpstr(g): | |
248 | + return g[1:-1] | |
249 | + | |
250 | +def split_xpath_last(xpath): | |
251 | + """split an XPath of the form /foo/bar/baz into /foo/bar and baz""" | |
252 | + xpath = xpath.strip() | |
253 | + m = _re_splitSimpleLast.match(xpath) | |
254 | + if m: | |
255 | + return (m.group(1), [(m.group(2), None)]) # requesting an element to exist | |
256 | + m = _re_splitSimpleLastEqValue.match(xpath) | |
257 | + if m: | |
258 | + return (m.group(1), [(m.group(2), _extract_xpstr(m.group(3)))]) # requesting an element to exist with an inner text | |
259 | + | |
260 | + m = _re_splitSimpleAttrLast.match(xpath) | |
261 | + if m: | |
262 | + return (m.group(1), [(m.group(2), None)]) # requesting an attribute to exist | |
263 | + m = _re_splitSimpleAttrLastEqValue.match(xpath) | |
264 | + if m: | |
265 | + return (m.group(1), [(m.group(2), _extract_xpstr(m.group(3)))]) # requesting an attribute to exist with a value | |
266 | + | |
267 | + m = _re_splitSubLast.match(xpath) | |
268 | + if m: | |
269 | + content = map(lambda x: x.strip(), m.group(3).split(" and ")) | |
270 | + | |
271 | + return (m.group(1), [('/'+m.group(2), content )] ) | |
272 | + | |
273 | + m = _re_splitOnlyEqValue.match(xpath) | |
274 | + if m: | |
275 | + return (m.group(1), [("", _extract_xpstr(m.group(2)))]) # requesting a change of inner text | |
276 | + return (xpath, []) | |
277 | + | |
278 | +def nsnameToClark(name, namespaces): | |
279 | + if ":" in name: | |
280 | + (nsname, rawname) = name.split(":") | |
281 | + return "{{{0}}}{1}".format(namespaces[nsname], rawname) | |
282 | + else: | |
283 | + # no namespace name here | |
284 | + return name | |
285 | + | |
286 | +def check_or_make_target(module, tree, xpath, namespaces): | |
287 | + (inner_xpath, changes) = split_xpath_last(xpath) | |
288 | + if (inner_xpath == xpath) or (changes == None): | |
289 | + abort(module, "Can't process Xpath " + xpath + " in order to spawn nodes! tree is " + etree.tostring(tree, pretty_print=True)) | |
290 | + return False | |
291 | + | |
292 | + changed = False | |
293 | + | |
294 | + if not is_node(tree, inner_xpath, namespaces): | |
295 | + changed = check_or_make_target(module, tree, inner_xpath, namespaces) | |
296 | + | |
297 | + if is_node(tree, inner_xpath, namespaces) and changes: # we test again after calling check_or_make_target | |
298 | + for (eoa, eoa_value) in changes: | |
299 | + if eoa and eoa[0] != '@' and eoa[0] != '/': | |
300 | + # implicitly creating an element | |
301 | + new_kids = children_to_nodes(module, [nsnameToClark(eoa, namespaces)], "yaml") | |
302 | + if eoa_value: | |
303 | + for nk in new_kids: | |
304 | + nk.text = eoa_value | |
305 | + | |
306 | + for node in tree.xpath(inner_xpath, namespaces=namespaces): | |
307 | + if not module.check_mode: node.extend(new_kids) | |
308 | + changed = True | |
309 | + #abort(module, "now tree=" + etree.tostring(tree, pretty_print=True)) | |
310 | + elif eoa and eoa[0] == '/': | |
311 | + element = eoa[1:] | |
312 | + new_kids = children_to_nodes(module, [nsnameToClark(element, namespaces)], "yaml") | |
313 | + | |
314 | + for node in tree.xpath(inner_xpath, namespaces=namespaces): | |
315 | + if not module.check_mode: node.extend(new_kids) | |
316 | + for nk in new_kids: | |
317 | + for subexpr in eoa_value: | |
318 | + #abort(module, "element="+element+" subexpr="+str(subexpr)+" node="+etree.tostring(node, pretty_print=True)+ | |
319 | + # " now tree=" + etree.tostring(tree, pretty_print=True)) | |
320 | + check_or_make_target(module, nk, "./"+subexpr, namespaces) | |
321 | + changed = True | |
322 | + | |
323 | + #abort(module, "now tree=" + etree.tostring(tree, pretty_print=True)) | |
324 | + elif eoa == "": | |
325 | + for node in tree.xpath(inner_xpath, namespaces=namespaces): | |
326 | + if (node.text != eoa_value): | |
327 | + node.text = eoa_value | |
328 | + changed = True | |
329 | + | |
330 | + elif eoa and eoa[0] == '@': | |
331 | + attribute = nsnameToClark(eoa[1:], namespaces) | |
332 | + | |
333 | + for element in tree.xpath(inner_xpath, namespaces=namespaces): | |
334 | + changing = (not element.attrib.has_key(attribute)) or (element.attrib.get(attribute) != eoa_value) | |
335 | + | |
336 | + if not module.check_mode and changing: | |
337 | + changed = changed or changing | |
338 | + if eoa_value is None: | |
339 | + value = "" | |
340 | + else: | |
341 | + value = eoa_value | |
342 | + element.attrib[attribute] = value | |
343 | + | |
344 | + #abort(module, "arf "+xpath+" changing="+str(changing)+" as curval="+str(element.get(attribute))+" changed tree=" + etree.tostring(tree, pretty_print=True)) | |
345 | + | |
346 | + | |
347 | + else: | |
348 | + abort(module, "unknown tree transformation=" + etree.tostring(tree, pretty_print=True)) | |
349 | + | |
350 | + return changed | |
351 | + | |
352 | + | |
353 | +def ensure_xpath_exists(module, tree, xpath, namespaces): | |
354 | + changed = False | |
355 | + | |
356 | + if not is_node(tree, xpath, namespaces): | |
357 | + changed = check_or_make_target(module, tree, xpath, namespaces) | |
358 | + | |
359 | + finish(module, tree, xpath, namespaces, changed) | |
360 | + | |
361 | +def set_target_inner(module, tree, xpath, namespaces, attribute, value): | |
362 | + changed = False | |
363 | + | |
364 | + try: | |
365 | + if not is_node(tree, xpath, namespaces): | |
366 | + changed = check_or_make_target(module, tree, xpath, namespaces) | |
367 | + except Exception, e: | |
368 | + abort(module, "Xpath " + xpath + " causes a failure: "+str(e)+ "\n" + traceback.format_exc(e)+"\n -- tree is " + etree.tostring(tree, pretty_print=True)) | |
369 | + | |
370 | + if not is_node(tree, xpath, namespaces): | |
371 | + abort(module, "Xpath " + xpath + " does not reference a node! tree is " + etree.tostring(tree, pretty_print=True)) | |
372 | + | |
373 | + for element in tree.xpath(xpath, namespaces=namespaces): | |
374 | + if not attribute: | |
375 | + changed = changed or (element.text != value) | |
376 | + if not module.check_mode and (element.text != value): element.text = value | |
377 | + else: | |
378 | + changed = changed or (element.get(attribute) != value) | |
379 | + if ":" in attribute: | |
380 | + attr_ns, attr_name = attribute.split(":") | |
381 | + attribute = "{{{0}}}{1}".format(namespaces[attr_ns], attr_name) | |
382 | + if not module.check_mode and (element.get(attribute) != value): element.set(attribute, value) | |
383 | + | |
384 | + return changed | |
385 | + | |
386 | +def set_target(module, tree, xpath, namespaces, attribute, value): | |
387 | + changed = set_target_inner(module, tree, xpath, namespaces, attribute, value) | |
388 | + finish(module, tree, xpath, namespaces, changed) | |
389 | + | |
390 | +def pretty(module, tree): | |
391 | + xml_string = etree.tostring(tree, xml_declaration=True, encoding='UTF-8', pretty_print=module.params['pretty_print']) | |
392 | + changed = False | |
393 | + | |
394 | + if module.params['path']: | |
395 | + xml_file = os.path.expanduser(module.params['path']) | |
396 | + | |
397 | + xml_content = open(xml_file) | |
398 | + try: | |
399 | + if xml_string != xml_content.read(): | |
400 | + changed = True | |
401 | + tree.write(xml_file, xml_declaration=True, encoding='UTF-8', pretty_print=module.params['pretty_print']) | |
402 | + finally: | |
403 | + xml_content.close() | |
404 | + | |
405 | + module.exit_json(changed=changed) | |
406 | + | |
407 | + if module.params['xmlstring']: | |
408 | + if xml_string != module.params['xmlstring']: | |
409 | + changed = True | |
410 | + | |
411 | + module.exit_json(changed=changed, xmlstring=xml_string) | |
412 | + | |
413 | +def get_element_text(module, tree, xpath, namespaces): | |
414 | + if not is_node(tree, xpath, namespaces): | |
415 | + abort(module, "Xpath " + xpath + " does not reference a node!") | |
416 | + | |
417 | + elements = [] | |
418 | + for element in tree.xpath(xpath, namespaces=namespaces): | |
419 | + elements.append({element.tag: element.text}) | |
420 | + | |
421 | + finish(module, tree, xpath, namespaces, changed=False, msg=len(elements), hitcount=len(elements), matches=elements) | |
422 | + | |
423 | +def get_element_attr(module, tree, xpath, namespaces): | |
424 | + if not is_node(tree, xpath, namespaces): | |
425 | + abort(module, "Xpath " + xpath + " does not reference a node!") | |
426 | + | |
427 | + elements = [] | |
428 | + for element in tree.xpath(xpath, namespaces=namespaces): | |
429 | + child = {} | |
430 | + for key in element.keys(): | |
431 | + value = element.get(key) | |
432 | + child.update({key: value}) | |
433 | + elements.append({element.tag: child}) | |
434 | + | |
435 | + finish(module, tree, xpath, namespaces, changed=False, msg=len(elements), hitcount=len(elements), matches=elements) | |
436 | + | |
437 | +def child_to_element(module, child, in_type): | |
438 | + if in_type == 'xml': | |
439 | + infile = BytesIO(child.encode('utf-8')) | |
440 | + | |
441 | + try: | |
442 | + parser = etree.XMLParser() | |
443 | + node = etree.parse(infile, parser) | |
444 | + return node.getroot() | |
445 | + except etree.XMLSyntaxError, e: | |
446 | + module.fail_json( | |
447 | + msg="Error while parsing child element: %s" % | |
448 | + str(e)) | |
449 | + elif in_type == 'yaml': | |
450 | + ch_type = type(child) | |
451 | + if ch_type == str or ch_type == unicode: | |
452 | + return etree.Element(child) | |
453 | + elif ch_type == dict: | |
454 | + if len(child) > 1: | |
455 | + abort(module, "Can only create children from hashes with one key") | |
456 | + | |
457 | + (key, value) = child.items()[0] | |
458 | + if type(value) == dict: | |
459 | + children = value.pop('_', None) | |
460 | + | |
461 | + node = etree.Element(key, value) | |
462 | + | |
463 | + if children is not None: | |
464 | + if type(children) != list: | |
465 | + abort(module, "Invalid children type: %s, must be list." % str(type(children))) | |
466 | + | |
467 | + subnodes = children_to_nodes(module, children) | |
468 | + node.extend(subnodes) | |
469 | + else: | |
470 | + node = etree.Element(key) | |
471 | + node.text = value | |
472 | + return node | |
473 | + else: | |
474 | + abort(module, "Invalid child type: %s. Children must be either strings or hashes." % str(ch_type)) | |
475 | + else: | |
476 | + abort(module, "Invalid child input type: %s. Type must be either xml or yaml." % in_type) | |
477 | + | |
478 | +def children_to_nodes(module=None, children=[], type='yaml'): | |
479 | + """turn a str/hash/list of str&hash into a list of elements""" | |
480 | + return [child_to_element(module, child, type) for child in children] | |
481 | + | |
482 | +def abort(m, msg): | |
483 | + m.fail_json(msg=msg) | |
484 | + | |
485 | +def finish(m, tree, xpath, namespaces, changed=False, msg="", hitcount=0, matches=[]): | |
486 | + if not changed: | |
487 | + m.exit_json(changed=changed,actions={"xpath": xpath, "namespaces": namespaces, "ensure": m.params['ensure']}, msg=msg, count=hitcount, matches=matches) | |
488 | + | |
489 | + if m.params['path']: | |
490 | + xml_file = os.path.expanduser(m.params['path']) | |
491 | + tree.write(xml_file, xml_declaration=True, encoding='UTF-8', pretty_print=m.params['pretty_print']) | |
492 | + m.exit_json(changed=changed,actions={"xpath": xpath, "namespaces": namespaces, "ensure": m.params['ensure']}, msg=msg, count=hitcount, matches=matches) | |
493 | + | |
494 | + if m.params['xmlstring']: | |
495 | + xml_string = etree.tostring(tree, xml_declaration=True, encoding='UTF-8', pretty_print=m.params['pretty_print']) | |
496 | + m.exit_json(changed=changed,actions={"xpath": xpath, "namespaces": namespaces, "ensure": m.params['ensure']}, msg=msg, count=hitcount, matches=matches, xmlstring=xml_string) | |
497 | + | |
498 | +def decode(value): | |
499 | + # Convert value to unicode to use with lxml | |
500 | + if not value or isinstance(value, unicode): | |
501 | + return value | |
502 | + elif isinstance(value, str): | |
503 | + return value.decode('utf-8') | |
504 | + elif isinstance(value, list): | |
505 | + return [decode(v) for v in value] | |
506 | + elif isinstance(value, dict): | |
507 | + return dict((key, decode(val)) for key, val in value.iteritems()) | |
508 | + else: | |
509 | + raise AttributeError('Undecodable value: type=%s, value=%s' % | |
510 | + (type(value), value)) | |
511 | + | |
512 | +def main(): | |
513 | + module = AnsibleModule( | |
514 | + argument_spec=dict( | |
515 | + path=dict(required=False, default='', aliases=['dest', 'file']), | |
516 | + xmlstring=dict(required=False, default=''), | |
517 | + xpath=dict(required=False, default='/'), | |
518 | + namespaces=dict(required=False, default={}, type='dict'), | |
519 | + ensure=dict(required=False, default='present', choices=['absent', 'present']), | |
520 | + value=dict(required=False, default=None), | |
521 | + attribute=dict(required=False, default=None), | |
522 | + add_children=dict(required=False, default=None, type='list'), | |
523 | + set_children=dict(required=False, default=None, type='list'), | |
524 | + count=dict(required=False, default=None, type='bool'), | |
525 | + print_match=dict(required=False, default=None, type='bool'), | |
526 | + pretty_print=dict(required=False, default=False, type='bool'), | |
527 | + content=dict(required=False, default=None, choices=['attribute', 'text']), | |
528 | + input_type=dict(required=False, default='yaml', choices=['yaml', 'xml']) | |
529 | + ), | |
530 | + supports_check_mode=True, | |
531 | + mutually_exclusive = [ | |
532 | + ['value','set_children'], | |
533 | + ['value','add_children'], | |
534 | + ['set_children', 'add_children'], | |
535 | + ['path', 'xmlstring'], | |
536 | + ['content','set_children'], | |
537 | + ['content','add_children'], | |
538 | + ['content','value'], | |
539 | + ] | |
540 | + ) | |
541 | + | |
542 | + xml_file = os.path.expanduser(module.params['path']) | |
543 | + xml_string = module.params['xmlstring'] | |
544 | + xpath = module.params['xpath'] | |
545 | + namespaces = module.params['namespaces'] | |
546 | + ensure = module.params['ensure'] | |
547 | + value = decode(module.params['value']) | |
548 | + attribute = module.params['attribute'] | |
549 | + set_children = decode(module.params['set_children']) | |
550 | + add_children = decode(module.params['add_children']) | |
551 | + pretty_print = module.params['pretty_print'] | |
552 | + content = module.params['content'] | |
553 | + input_type = module.params['input_type'] | |
554 | + | |
555 | + ################################################################## | |
556 | + # Check if the file exists | |
557 | + # No: abort | |
558 | + if xml_string: | |
559 | + infile = BytesIO(xml_string.encode('utf-8')) | |
560 | + elif os.path.isfile(xml_file): | |
561 | + infile = file(xml_file, 'r') | |
562 | + else: | |
563 | + module.fail_json( | |
564 | + msg="The target XML source does not exist: %s" % | |
565 | + xml_file) | |
566 | + | |
567 | + # Try to parse in the target XML file | |
568 | + try: | |
569 | + parser = etree.XMLParser(remove_blank_text=pretty_print) | |
570 | + x = etree.parse(infile, parser) | |
571 | + except etree.XMLSyntaxError, e: | |
572 | + module.fail_json( | |
573 | + msg="Error while parsing file: %s" % | |
574 | + str(e)) | |
575 | + | |
576 | + if module.params['print_match']: | |
577 | + print_match(module, x, xpath, namespaces) | |
578 | + | |
579 | + if module.params['count']: | |
580 | + count(module, x, xpath, namespaces) | |
581 | + | |
582 | + if content == 'attribute': | |
583 | + get_element_attr(module, x, xpath, namespaces) | |
584 | + elif module.params['content'] == 'text': | |
585 | + get_element_text(module, x, xpath, namespaces) | |
586 | + | |
587 | + # module.fail_json(msg="OK. Well, etree parsed the xml file...") | |
588 | + | |
589 | + # module.exit_json(what_did={"foo": "bar"}, changed=True) | |
590 | + | |
591 | + ################################################################## | |
592 | + # File exists: | |
593 | + # Ensure: | |
594 | + if ensure == 'absent': | |
595 | + # - absent: delete xpath target | |
596 | + delete_xpath_target(module, x, xpath, namespaces) | |
597 | + # Exit | |
598 | + # - present: carry on | |
599 | + | |
600 | + ################################################################## | |
601 | + # children && value both set?: should have already aborted by now | |
602 | + ################################################################## | |
603 | + | |
604 | + ################################################################## | |
605 | + # add_children && set_children both set?: should have already aborted by now | |
606 | + ################################################################## | |
607 | + | |
608 | + ################################################################## | |
609 | + # set_children set? | |
610 | + # Yes: Set children of target | |
611 | + if module.params['set_children']: | |
612 | + set_target_children(module, x, xpath, namespaces, set_children, input_type) | |
613 | + | |
614 | + ################################################################## | |
615 | + # add_children set? | |
616 | + # Yes: Add children to target | |
617 | + if module.params['add_children']: | |
618 | + add_target_children(module, x, xpath, namespaces, add_children, input_type) | |
619 | + | |
620 | + # No?: Carry on | |
621 | + | |
622 | + ################################################################## | |
623 | + # Is the xpath target an attribute selector? | |
624 | + # Yes: Set the attribute, exit | |
625 | + if module.params['value'] is not None: | |
626 | + set_target(module, x, xpath, namespaces, attribute, value) | |
627 | + | |
628 | + ################################################################## | |
629 | + # Format the xml only? | |
630 | + if module.params['pretty_print']: | |
631 | + pretty(module, x) | |
632 | + | |
633 | + ensure_xpath_exists(module, x, xpath, namespaces) | |
634 | + #abort(module, "don't know what to do") | |
635 | + | |
636 | +###################################################################### | |
637 | +from ansible.module_utils.basic import * | |
638 | +main() | ... | ... |
yml/all.yml
yml/bm-server.yml
yml/host_vars/alfmbm
yml/load-driver.yml
yml/mongodb.yml
yml/roles/bm-server/tasks/main.yml
... | ... | @@ -0,0 +1,16 @@ |
1 | +--- | |
2 | +- name: Remove all Tomcat webapps | |
3 | + file: name="{{ catalina_home }}/webapps/{{ item }}" state=absent | |
4 | + with_items: | |
5 | + - alfresco-benchmark-server | |
6 | + - alfresco-benchmark-server.war | |
7 | + when: tomcat_clean == True | |
8 | + | |
9 | +- name: Get Alfresco benchmark server artifact | |
10 | + get_url: | |
11 | + url: "{{ artifact_repo }}/{{ bm_server_path }}" | |
12 | + dest: "{{ catalina_home }}/webapps/alfresco-benchmark-server.war" | |
13 | + owner: "{{ tomcat_user }}" | |
14 | + group: "{{ tomcat_group }}" | |
15 | + mode: 0644 | |
16 | + | ... | ... |
yml/roles/common/tasks/dist.yml
... | ... | @@ -0,0 +1,23 @@ |
1 | +--- | |
2 | +- name: Load OS specific vars | |
3 | + include_vars: "{{ item }}" | |
4 | + with_first_found: | |
5 | + - "{{ ansible_os_family|lower }}.yml" | |
6 | + ignore_errors: true | |
7 | + | |
8 | +- name: Load distribution vars | |
9 | + include_vars: "{{ item }}" | |
10 | + with_first_found: | |
11 | + - "../vars/{{ ansible_distribution|lower }}.yml" | |
12 | + ignore_errors: true | |
13 | + | |
14 | +- name: Load major version vars | |
15 | + include_vars: "{{ item }}" | |
16 | + with_first_found: | |
17 | + - "../vars/{{ ansible_distribution|lower }}_{{ ansible_distribution_major_version|lower }}.yml" | |
18 | + ignore_errors: true | |
19 | + | |
20 | +- name: WARNING | |
21 | + debug: msg="your Linux distribution is quite outdated! Software version specified in your configuration may not be the one deployed" | |
22 | + when: warn_old | |
23 | + | ... | ... |
yml/roles/common/tasks/main.yml
yml/roles/common/tasks/packages.yml
... | ... | @@ -0,0 +1,16 @@ |
1 | +--- | |
2 | +- name: Setup required repositories (Debian-like systems) | |
3 | + apt_repository: repo="{{ item }}" filename=alfbm | |
4 | + when: ansible_pkg_mgr == "apt" and repo_list is defined | |
5 | + with_items: "{{ repo_list }}" | |
6 | + | |
7 | +- name: Install common packages (RedHat like systems) | |
8 | + yum: pkg={{ item }} | |
9 | + when: ansible_pkg_mgr == "yum" | |
10 | + with_items: "{{ common_pkg }}" | |
11 | + | |
12 | +- name: Install common packages (Debian like systems) | |
13 | + apt: name={{ item }} | |
14 | + when: ansible_pkg_mgr == "apt" | |
15 | + with_items: "{{ย common_pkg }}" | |
16 | + | ... | ... |
yml/roles/common/vars/centos.yml
yml/roles/common/vars/debian.yml
yml/roles/common/vars/debian_7.yml
yml/roles/common/vars/debian_8.yml
yml/roles/common/vars/redhat.yml
yml/roles/common/vars/ubuntu.yml
yml/roles/common/vars/ubuntu_14.yml
yml/roles/load-driver/tasks/main.yml
... | ... | @@ -0,0 +1,33 @@ |
1 | +--- | |
2 | +- name: Remove all Tomcat webapps | |
3 | + file: name="{{ catalina_home }}/webapps/{{ item }}" state=absent | |
4 | + with_items: | |
5 | + - alfresco-benchmark-tests-signup | |
6 | + - alfresco-benchmark-tests-signup.war | |
7 | + - alfresco-benchmark-tests-cmis | |
8 | + - alfresco-benchmark-tests-cmis.war | |
9 | + - alfresco-benchmark-tests-dataload | |
10 | + - alfresco-benchmark-tests-dataload.war | |
11 | + - alfresco-benchmark-tests-share | |
12 | + - alfresco-benchmark-tests-share.war | |
13 | + - alfresco-benchmark-tests-workflow | |
14 | + - alfresco-benchmark-tests-workflow.war | |
15 | + - alfresco-benchmark-tests-desktopsync | |
16 | + - alfresco-benchmark-tests-desktopsync.war | |
17 | + when: tomcat_clean == True | |
18 | + | |
19 | +- name: Get Alfresco benchmark tests artifacts | |
20 | + get_url: | |
21 | + url: "{{ artifact_repo }}/{{ item.artifact }}" | |
22 | + dest: "{{ catalina_home }}/webapps/{{ item.warfile }}.war" | |
23 | + owner: "{{ tomcat_user }}" | |
24 | + group: "{{ tomcat_group }}" | |
25 | + mode: 0644 | |
26 | + with_items: | |
27 | + - { artifact: "{{ tests_signup_path }}", warfile: 'alfresco-benchmark-tests-signup' } | |
28 | + - { artifact: "{{ tests_cmis_path }}", warfile: 'alfresco-benchmark-tests-cmis' } | |
29 | + - { artifact: "{{ tests_dataload_path }}", warfile: 'alfresco-benchmark-tests-dataload' } | |
30 | + - { artifact: "{{ย tests_share_path }}", warfile: 'alfresco-benchmark-tests-share' } | |
31 | + - { artifact: "{{ย tests_workflow_path }}", warfile: 'alfresco-benchmark-tests-workflow' } | |
32 | + - { artifact: "{{ย tests_desktopsync_path }}", warfile: 'alfresco-benchmark-tests-desktopsync' } | |
33 | + | ... | ... |
yml/roles/mongodb/handlers/main.yml
yml/roles/mongodb/tasks/config.yml
yml/roles/mongodb/tasks/dist.yml
... | ... | @@ -0,0 +1,23 @@ |
1 | +--- | |
2 | +- name: Load OS specific vars | |
3 | + include_vars: "{{ item }}" | |
4 | + with_first_found: | |
5 | + - "{{ ansible_os_family|lower }}.yml" | |
6 | + ignore_errors: true | |
7 | + | |
8 | +- name: Load distribution vars | |
9 | + include_vars: "{{ item }}" | |
10 | + with_first_found: | |
11 | + - "../vars/{{ ansible_distribution|lower }}.yml" | |
12 | + ignore_errors: true | |
13 | + | |
14 | +- name: Load major version vars | |
15 | + include_vars: "{{ item }}" | |
16 | + with_first_found: | |
17 | + - "../vars/{{ ansible_distribution|lower }}_{{ ansible_distribution_major_version|lower }}.yml" | |
18 | + ignore_errors: true | |
19 | + | |
20 | +- name: WARNING | |
21 | + debug: msg="your Linux distribution is quite outdated! Software version specified in your configuration may not be the one deployed" | |
22 | + when: warn_old | |
23 | + | ... | ... |
yml/roles/mongodb/tasks/main.yml
yml/roles/mongodb/tasks/packages.yml
... | ... | @@ -0,0 +1,17 @@ |
1 | +--- | |
2 | +- name: Add MongoDB repo key | |
3 | + apt_key: | |
4 | + keyserver: hkp://keyserver.ubuntu.com:80 | |
5 | + id: 0C49F3730359A14518585931BC711F9BA15703C6 | |
6 | + when: ansible_pkg_mgr == 'apt' | |
7 | + | |
8 | +- name: Set up MongoDB reposirtory | |
9 | + apt_repository: | |
10 | + repo: "{{ mongo_repo_url }}" | |
11 | + when: ansible_pkg_mgr == 'apt' | |
12 | + | |
13 | +- name: Install MongoDB | |
14 | + apt: | |
15 | + name: mongodb-org | |
16 | + when: ansible_pkg_mgr == 'apt' | |
17 | + | ... | ... |
yml/roles/mongodb/vars/centos_7.yml
yml/roles/mongodb/vars/debian.yml
yml/roles/mongodb/vars/debian_7.yml
yml/roles/mongodb/vars/debian_8.yml
yml/roles/mongodb/vars/ubuntu.yml
yml/roles/mongodb/vars/ubuntu_14.yml
yml/roles/selenium/tasks/main.yml
... | ... | @@ -0,0 +1,43 @@ |
1 | +--- | |
2 | +- name: Create selenium user | |
3 | + user: | |
4 | + name: selenium | |
5 | + system: yes | |
6 | + shell: /bin/false | |
7 | + home: /usr/local/share/selenium | |
8 | + comment: "Selenium Browser autamation user" | |
9 | + | |
10 | +- name: Get Selenium server | |
11 | + get_url: | |
12 | + url: "{{ selenium_url }}" | |
13 | + dest: "/usr/local/share/selenium/selenium-server-standalone-{{ selenium_version }}.jar" | |
14 | + mode: 0644 | |
15 | + | |
16 | +- name: Install Pseudo X server | |
17 | + apt: | |
18 | + name: xvfb | |
19 | + when: ansible_pkg_mgr == "apt" | |
20 | + | |
21 | +- name: Add Selenium Hub init script | |
22 | + template: | |
23 | + src: sysvinit-hub | |
24 | + dest: /etc/init.d/selenium-hub | |
25 | + mode: 0755 | |
26 | + when: inventory_hostname in groups['selenium-hub'] | |
27 | + | |
28 | +- name: Add Selenium Node init script | |
29 | + template: | |
30 | + src: sysvinit-node | |
31 | + dest: /etc/init.d/selenium-node | |
32 | + mode: 0755 | |
33 | + when: inventory_hostname in groups['load-driver'] | |
34 | + | |
35 | +- name: Enable Selenium service | |
36 | + service: | |
37 | + name: "{{ item }}" | |
38 | + state: started | |
39 | + enabled: yes | |
40 | + with_items: | |
41 | + - selenium-hub | |
42 | + - selenium-node | |
43 | + | ... | ... |
yml/roles/selenium/templates/sysvinit-hub
... | ... | @@ -0,0 +1,50 @@ |
1 | +#!/bin/bash | |
2 | + | |
3 | +DESC="Selenium server" | |
4 | +RUN_AS=selenium | |
5 | +JAVA_BIN=/usr/bin/java | |
6 | + | |
7 | +SELENIUM_DIR=/usr/local/share/selenium | |
8 | +PID_FILE="$SELENIUM_DIR/selenium-hub.pid" | |
9 | +JAR_FILE="$SELENIUM_DIR/selenium-server-standalone-{{ selenium_version }}.jar" | |
10 | +LOG_FILE="$SELENIUM_DIR/selenium-hub.log" | |
11 | +SELENIUM_PORT={{ selenium_hub_portnumber }} | |
12 | + | |
13 | +MAX_MEMORY="-Xmx1G" | |
14 | +STACK_SIZE="-Xss1024k" | |
15 | + | |
16 | +DAEMON_OPTS="$MAX_MEMORY -jar $JAR_FILE -log $LOG_FILE -role hub -newSessionWaitTimeout 5000 -timeout 300 -port $SELENIUM_PORT" | |
17 | + | |