~pfalcon/linaro-ci-dashboard/bzr_home

9.2.2 by Stevan Radakovic
Add jenkins_server model. Add lib/ to the pythonpath.
1
#!/usr/bin/env python
2
# Copyright (C) 2012 Linaro
3
#
4
# This file is part of linaro-ci-dashboard.
5
#
6
# linaro-ci-dashboard is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU Affero General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
10
#
11
# linaro-ci-dashboard is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU Affero General Public License for more details.
15
#
16
# You should have received a copy of the GNU Affero General Public License
17
# along with linaro-ci-dashboard.  If not, see <http://www.gnu.org/licenses/>.
18
19
from django.db import models
12.1.1 by Deepti B. Kalakeri
Adding changes to create /delete job on jenkins server
20
from django.conf import settings
41.2.1 by Stevan Radakovic
Add extended Jenkins library, add test file and empty custom command.
21
from lib.jenkins_dashboard import JenkinsDashboard
19.1.6 by Paul Sokolovsky
Move helpers.getClassLogger() to lib.logger.Logger.getClassLogger().
22
from lib.logger import Logger
24.2.1 by Georgy Redkozubov
Added initial job config support suggested by pfalcon for android-build.
23
from lib.template import TextTemplate, XMLTemplate
9.2.16 by Stevan Radakovic
Helper methods for sync and tests.
24
25.1.3 by Milo Casagrande
Fixed problem with android_build job send, cleaned imports.
25
9.2.2 by Stevan Radakovic
Add jenkins_server model. Add lib/ to the pythonpath.
26
class JenkinsServer(models.Model):
27
    class Meta:
9.2.29 by Stevan Radakovic
Rename jenkins server application, reset migrations.
28
        app_label = 'jenkinsserver'
9.2.2 by Stevan Radakovic
Add jenkins_server model. Add lib/ to the pythonpath.
29
30
    url = models.CharField(max_length=255)
9.2.3 by Stevan Radakovic
Create new app. Move models to it. Try to resolve jenkinsapi dependency problems.
31
    username = models.CharField(max_length=100)
32
    password = models.CharField(max_length=100)
9.2.2 by Stevan Radakovic
Add jenkins_server model. Add lib/ to the pythonpath.
33
9.2.13 by Stevan Radakovic
Add encoding to __init and non implemented sync_jobs.
34
    def __init__(self, *args, **kwargs):
35
        super(JenkinsServer, self).__init__(*args, **kwargs)
19.1.6 by Paul Sokolovsky
Move helpers.getClassLogger() to lib.logger.Logger.getClassLogger().
36
        self.log = Logger.getClassLogger(self)
41.2.1 by Stevan Radakovic
Add extended Jenkins library, add test file and empty custom command.
37
        self.jenkins = JenkinsDashboard(self.url,
9.2.29 by Stevan Radakovic
Rename jenkins server application, reset migrations.
38
                                       self.username.encode('utf-8'),
39
                                       self.password.encode('utf-8'))
9.2.13 by Stevan Radakovic
Add encoding to __init and non implemented sync_jobs.
40
25.1.12 by Milo Casagrande
Refactored method name.
41
    def create_or_update_loop(self, loop):
14.2.1 by Stevan Radakovic
Separate integration loop model from loop model.
42
        """ Create integration loop if it doesn't exist on Jenkins.
43
        Otherwise, update the existing one with new XML."""
44
19.1.3 by Paul Sokolovsky
Log when we create/update Jenkins job for a loop.
45
        self.log.info("Creating/updating Jenkins job for loop: %r", loop)
24.2.1 by Georgy Redkozubov
Added initial job config support suggested by pfalcon for android-build.
46
        jxml = self.create_job_xml(loop)
14.2.1 by Stevan Radakovic
Separate integration loop model from loop model.
47
        if not self.jenkins.job_exists(loop.name):
48
            self.create_job(loop.name, jxml)
49
        else:
50
            self.update_job(loop.name, jxml)
51
52
    def sync_jobs_and_builds(self):
53
        """Sync loops and builds with jobs on jenkins server.
54
55
        Query only ci-dashboard existing jobs and builds on jenkins
14.2.4 by Stevan Radakovic
Add new sync command for jenkins and CI loop build sync. Also refactor the sync method in jenkinsserver model.
56
        and update fields.
57
        This method contains few hacks for build info gathering since
58
        python-jenkins library does not support the get build info method.
59
        """
60
61
        # Go through all the loops in CI
62
        for loop in self.loop_set.all():
63
14.2.1 by Stevan Radakovic
Separate integration loop model from loop model.
64
            if self.jenkins.job_exists(loop.name):
14.2.4 by Stevan Radakovic
Add new sync command for jenkins and CI loop build sync. Also refactor the sync method in jenkinsserver model.
65
                # Get the jenkins build dict for each loop.
66
                job_info = self.jenkins.get_job_info(loop.name)
67
                jenkins_builds = job_info["builds"]
68
                for build in loop.loopbuild_set.all():
69
                    for jenkins_build in jenkins_builds:
14.2.9 by Stevan Radakovic
Add remote_number functionality to CI loop build.
70
                        # If the build number and loop remote_number match,
71
                        # update the build info in CI.
72
                        if build.remote_number and \
73
                            jenkins_build["number"] == build.remote_number:
41.2.5 by Stevan Radakovic
A bit of refactoring.
74
                            self.get_build_info()
75
76
    def get_build_info(self, build):
77
        jenkins_build = self.jenkins.get_build_info(build.loop.name,
78
                                                    build.remote_number)
79
        # Duration in jenkins is presented in milliseconds
48.1.4 by Stevan Radakovic
Fix from code review.
80
        if jenkins_build.get("duration", None):
81
            build.duration = float(jenkins_build.get("duration", None)) / 1000
48.1.2 by Stevan Radakovic
Fix non-existing fields in jenkins build json case.
82
48.1.4 by Stevan Radakovic
Fix from code review.
83
        if jenkins_build.get("result", None):
84
            build.status = jenkins_build.get("result", None).lower()
41.2.5 by Stevan Radakovic
A bit of refactoring.
85
        # TODO: Add build result xml, but from where?
86
        build.save()
87
88
    def sync_unfinished_builds(self):
41.2.3 by Stevan Radakovic
Implement get_build_output and finish custom command implementation.
89
        from frontend.models.loop_build import LoopBuild
90
        builds = LoopBuild.objects.filter(
91
            status__in=LoopBuild.NON_FINISHED_STATUSES)
92
        for build in builds:
41.2.5 by Stevan Radakovic
A bit of refactoring.
93
            self.get_build_info(build)
41.2.3 by Stevan Radakovic
Implement get_build_output and finish custom command implementation.
94
12.1.1 by Deepti B. Kalakeri
Adding changes to create /delete job on jenkins server
95
    def create_job(self, jname, jxml):
96
        """ Creates a new job on jenkins if its  not already present """
12.1.4 by Deepti B. Kalakeri
Addressing the review comments
97
        jname = jname.replace(' ', '%20').strip()
14.2.1 by Stevan Radakovic
Separate integration loop model from loop model.
98
        self.jenkins.create_job(jname, jxml)
99
        self.jenkins.enable_job(jname)
100
101
    def update_job(self, jname, jxml):
102
        """ Creates a new job on jenkins if its  not already present """
103
        jname = jname.replace(' ', '%20').strip()
104
        self.jenkins.reconfig_job(jname, jxml)
12.1.1 by Deepti B. Kalakeri
Adding changes to create /delete job on jenkins server
105
106
    def delete_job(self, jname):
107
        """ Deleted a job on jenkins if present """
108
        if self.jenkins.job_exists(jname):
109
            self.jenkins.delete_job(jname)
14.2.5 by Stevan Radakovic
PEP8 fixes.
110
24.2.1 by Georgy Redkozubov
Added initial job config support suggested by pfalcon for android-build.
111
    def create_job_xml(self, loop):
112
        "Prepare the config.xml to be used for the job."
25.1.1 by Milo Casagrande
Merged gesha code, and fixes.
113
        # Get generic serialization data.
114
        loop_params = loop.json()
51.1.2 by Paul Sokolovsky
Make default 'assigned_node' param be equal to loop class name.
115
        # If loop didn't specify label expression for build slave selection,
116
        # by default use loop class as such.
117
        if 'assigned_node' not in loop_params:
51.1.3 by Paul Sokolovsky
Use loop.type instead of Python class name as default assigned_node value.
118
            loop_params['assigned_node'] = loop.type
53 by Paul Sokolovsky
Use Loop type instead of Python class name as job/script template names.
119
        template_name = loop.type
25.1.11 by Milo Casagrande
Fixed JenkinsServer to use new parameters.
120
121
        # We need to handle the CONFIG parameter as a base64 encoded string.
122
        # At the moment used only by Android builds.
123
        loop_params['base64_config'] = loop.base64_config()
124
125
        # Check if the build is restricted, assign appropriate nodes.
51.1.2 by Paul Sokolovsky
Make default 'assigned_node' param be equal to loop class name.
126
        # TODO: This should be handled on the level on particular Loop,
127
        # not here!
25.1.11 by Milo Casagrande
Fixed JenkinsServer to use new parameters.
128
        if loop.is_restricted:
129
            loop_params['assigned_node'] = 'private &amp;&amp; natty'
25.1.1 by Milo Casagrande
Merged gesha code, and fixes.
130
131
        build_script = TextTemplate(settings.BUILD_SCRIPT_TEMPLATE\
132
            % template_name).render(loop_params)
133
        loop_params['build_script'] = build_script
134
24.2.1 by Georgy Redkozubov
Added initial job config support suggested by pfalcon for android-build.
135
        xml = XMLTemplate(settings.JENKINS_JOB_TEMPLATE \
25.1.1 by Milo Casagrande
Merged gesha code, and fixes.
136
               % template_name).render(loop_params)
137
24.2.1 by Georgy Redkozubov
Added initial job config support suggested by pfalcon for android-build.
138
        return xml
14 by Stevan Radakovic
Add list and detail page for CI loops. Integrate jQuery and implement 'Schedule Build' functionality. Reviewed by deeptik, dooferlad.
139
25.1.2 by Milo Casagrande
Added parameters for build, fixed string concat problem.
140
    def schedule_job_build(self, jobname, parameters=None):
14.2.9 by Stevan Radakovic
Add remote_number functionality to CI loop build.
141
        """Trigger build job on jenkins. Return the next build number."""
25.1.2 by Milo Casagrande
Added parameters for build, fixed string concat problem.
142
        self.jenkins.build_job(jobname, parameters)
14.2.9 by Stevan Radakovic
Add remote_number functionality to CI loop build.
143
        job_info = self.jenkins.get_job_info(jobname)
144
        return job_info["nextBuildNumber"]