aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorPaul Sokolovsky <paul.sokolovsky@linaro.org>2011-11-18 05:07:26 +0200
committerPaul Sokolovsky <paul.sokolovsky@linaro.org>2011-11-18 05:07:26 +0200
commit7cfa06224f6fdf02a5ce5dc543c031a8f93df02b (patch)
tree8dbfd8f5098e9b1bc1781d3fb587c243d26b7867 /utils
parent4137e1fae265afbbf584dd13291ace986ff9e316 (diff)
Create new utils dir, move mange-jobs util there.
Diffstat (limited to 'utils')
-rw-r--r--utils/mangle-jobs/add-logparser.mangle20
-rwxr-xr-xutils/mangle-jobs/mangle-jobs127
-rw-r--r--utils/mangle-jobs/reset-cron.mangle8
-rw-r--r--utils/mangle-jobs/test.mangle6
-rw-r--r--utils/mangle-jobs/update-artifacts.mangle5
-rw-r--r--utils/mangle-jobs/update-jobs.mangle9
6 files changed, 175 insertions, 0 deletions
diff --git a/utils/mangle-jobs/add-logparser.mangle b/utils/mangle-jobs/add-logparser.mangle
new file mode 100644
index 0000000..597a66e
--- /dev/null
+++ b/utils/mangle-jobs/add-logparser.mangle
@@ -0,0 +1,20 @@
+# Add Log Parser plugin application to jobs
+
+#from lxml.etree import Element
+from lxml.etree import fromstring
+
+def mangle(tree):
+ if tree.xpath("//hudson.plugins.logparser.LogParserPublisher"):
+ # Already there
+ return
+ tag = tree.xpath('//publishers')[0]
+ node = fromstring("""\
+ <hudson.plugins.logparser.LogParserPublisher>
+ <unstableOnWarning>false</unstableOnWarning>
+ <failBuildOnError>false</failBuildOnError>
+ <parsingRulesPath>/var/lib/jenkins/userContent/android.parse</parsingRulesPath>
+ </hudson.plugins.logparser.LogParserPublisher>
+""")
+ tag.append(node)
+ node.getprevious().tail += " "
+ node.tail = "\n "
diff --git a/utils/mangle-jobs/mangle-jobs b/utils/mangle-jobs/mangle-jobs
new file mode 100755
index 0000000..cd71ec6
--- /dev/null
+++ b/utils/mangle-jobs/mangle-jobs
@@ -0,0 +1,127 @@
+#!/usr/bin/python
+"""Helper to mass-edit jobs in jenkins.
+
+"""
+
+###############################################################################
+# Copyright (c) 2011 Linaro
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+###############################################################################
+
+import base64
+from contextlib import nested
+import json
+import os
+import sys
+from tempfile import NamedTemporaryFile
+import urllib2
+import optparse
+
+from lxml.etree import fromstring, tostring
+
+
+optparser = optparse.OptionParser(usage="%prog <mangle script>")
+optparser.add_option("--user",
+ help="Jenkins username")
+optparser.add_option("--passwd-file", metavar="FILE",
+ help="File holding Jenkins password")
+optparser.add_option("--really", action="store_true",
+ help="Actually perform changes")
+optparser.add_option("--limit", type="int", default=-1,
+ help="Change at most LIMIT jobs")
+optparser.add_option("--file",
+ help="Process a file instead of all jobs on a remote server")
+
+options, args = optparser.parse_args(sys.argv[1:])
+if len(args) != 1:
+ optparser.error("Wrong number of arguments")
+
+d = {}
+execfile(args[0], d, d)
+mangler = d['mangle']
+
+password = None
+if options.passwd_file:
+ password = open(options.passwd_file).read().strip()
+auth_headers = {
+ 'Authorization': 'Basic %s' % (
+ base64.encodestring('%s:%s' % (options.user, password))[:-1],),
+ }
+
+def _authJenkins(jenkins_path, data=None, extra_headers=None):
+ """Make an authenticated request to jenkins.
+
+ @param jenkins_path: The path on the Jenkins instance to make the request
+ to.
+ @param data: Data to include in the request (if this is not None the
+ request will be a POST).
+ @param extra_headers: A dictionary of extra headers that will passed in
+ addition to Authorization.
+ @raises urllib2.HTTPError: If the response is not a HTTP 200.
+ @returns: the body of the response.
+ """
+ headers = auth_headers.copy()
+ if extra_headers:
+ headers.update(extra_headers)
+ req = urllib2.Request(
+ 'http://localhost:9090/jenkins/' + jenkins_path, data, headers)
+ resp = urllib2.urlopen(req)
+ return resp.read()
+
+def getJobConfig(job_name):
+ return _authJenkins('job/' + job_name + '/config.xml')
+
+def postConfig(url, configXml):
+ _authJenkins(url, configXml, {'Content-Type': 'text/xml'})
+
+def render_xml(tree):
+ text = tostring(tree, xml_declaration=True, encoding='UTF-8')
+ line1, rest = text.split("\n", 1)
+ line1 = line1.replace("'", '"')
+ return line1 + rest
+
+def show_diff(old, new):
+ with nested(NamedTemporaryFile(), NamedTemporaryFile()) as (a, b):
+ a.write(old)
+ b.write(new)
+ a.flush(); b.flush()
+ os.system('diff -u %s %s' % (a.name, b.name))
+ print
+
+def process_remote_jenkins():
+ jobs = json.load(urllib2.urlopen('http://localhost:9090/jenkins/api/json?tree=jobs[name]'))
+ names = [job['name'] for job in jobs['jobs']]
+ names = [name for name in names if name == 'blank' or '_' in name]
+ limit = options.limit
+ for name in names:
+ if limit == 0:
+ break
+ limit -= 1
+ print "Processing:" + name
+ sys.stdout.flush()
+ text = getJobConfig(name)
+ tree = fromstring(text)
+ mangler(tree)
+ new_text = render_xml(tree)
+ if not options.really:
+ show_diff(text, new_text)
+ else:
+ if type(new_text) == type(u""):
+ new_text = new_text.encode("utf8")
+ postConfig(str('job/' + name + '/config.xml'), new_text)
+
+def main():
+ if options.file:
+ text = open(options.file).read()
+ tree = fromstring(text)
+ mangler(tree)
+ new_text = render_xml(tree)
+ show_diff(text, new_text)
+ else:
+ process_remote_jenkins()
+
+if __name__ == "__main__":
+ main()
diff --git a/utils/mangle-jobs/reset-cron.mangle b/utils/mangle-jobs/reset-cron.mangle
new file mode 100644
index 0000000..3848ac4
--- /dev/null
+++ b/utils/mangle-jobs/reset-cron.mangle
@@ -0,0 +1,8 @@
+# Reset any triggers of a job, cron triggers in particular (but not limited)
+# This is useful for sandboxes to avoid unexpected cron jobs runs
+
+def mangle(tree):
+ tag = tree.xpath('//triggers')[0]
+ for t in tag:
+ tag.remove(t)
+ tag.text = None
diff --git a/utils/mangle-jobs/test.mangle b/utils/mangle-jobs/test.mangle
new file mode 100644
index 0000000..9fbcaa2
--- /dev/null
+++ b/utils/mangle-jobs/test.mangle
@@ -0,0 +1,6 @@
+
+def mangle(tree):
+ tags = tree.xpath('/project/description')
+ if not tags: return
+ tag = tags[0]
+ tag.text = 'Excitingly created.'
diff --git a/utils/mangle-jobs/update-artifacts.mangle b/utils/mangle-jobs/update-artifacts.mangle
new file mode 100644
index 0000000..33c8066
--- /dev/null
+++ b/utils/mangle-jobs/update-artifacts.mangle
@@ -0,0 +1,5 @@
+new_value = "build/out/target/*/*/*.img,build/out/target/*/*/*.tar.bz2,build/out/target/*/*/MD5SUMS,build/out/*.tar.bz2,build/out/*.xml,build/out/*_config,build/out/lava-job-info"
+
+def mangle(tree):
+ tags = tree.xpath('/project/publishers/hudson.tasks.ArtifactArchiver/artifacts')
+ tags[0].text = new_value
diff --git a/utils/mangle-jobs/update-jobs.mangle b/utils/mangle-jobs/update-jobs.mangle
new file mode 100644
index 0000000..a83d815
--- /dev/null
+++ b/utils/mangle-jobs/update-jobs.mangle
@@ -0,0 +1,9 @@
+new_cmd = '''\
+rm -rf build-tools
+bzr get http://bazaar.launchpad.net/~linaro-infrastructure/linaro-android-build-tools/trunk build-tools
+build-tools/node/build us-east-1.ec2-git-mirror.linaro.org "$CONFIG"
+'''
+
+def mangle(tree):
+ tags = tree.xpath('/project/builders/hudson.tasks.Shell/command')
+ tags[0].text = new_cmd