Exemplo n.º 1
0
 def getStatus():
     rid = request.args.get("rid")
     JS_URL = app.config["JENKINS_URL"]
     app.logger.debug('Connecting to Jenkins %s as %s', JS_URL,
                      app.config["UID"])
     js = JenkinsServer(JS_URL,
                        username=app.config["UID"],
                        password=app.config["PWD"])
     app.logger.debug('Connected')
     app.logger.info('Hello from Jenkins %s', js.get_version())
     allBuilds = js.get_job_info(app.config["FOLDER_NAME"] + '/' +
                                 app.config["PIPELINE_NAME"],
                                 fetch_all_builds=True)
     ret = "{"
     for build in allBuilds['builds']:
         bi = js.get_build_info(
             app.config["FOLDER_NAME"] + '/' + app.config["PIPELINE_NAME"],
             build['number'])
         if (bi['displayName'] == rid):
             ret += " \"displayName\": \"" + str(bi['displayName']) + "\", "
             ret += " \"buildNumber\": \"" + str(build['number']) + "\", "
             ret += " \"building\": \"" + str(bi['building']) + "\", "
             ret += " \"result\": \"" + str(bi['result']) + "\""
             continue
     ret += "}"
     return ret
Exemplo n.º 2
0
def main(build_url, sleeptime=15, pushover=False):
    if pushover and not have_pushover:
        raise SystemExit("ERROR: to use pushover notifications, please `pip install python-pushover` and configure it.")
    job_name, build_no = get_job_name_and_build_number(build_url)
    jenkins_url = get_jenkins_base_url(build_url)
    logger.debug("Connecting to Jenkins...")
    """
    NOTE: this is using unauthenticated / anonymous access.
    If that doesn't work for you, change this to something like:
    j = Jenkins(jenkins_url, 'username', 'password')
    """
    j = Jenkins(jenkins_url)
    logger.debug("Connected.")
    if build_no is None:
        jobinfo = j.get_job_info(job_name)
        build_no = jobinfo['nextBuildNumber'] - 1
        print("Using latest build, #{b}".format(b=build_no))
    build_url = get_formal_build_url(jenkins_url, job_name, build_no)
    print("Watching job {j} #{b} until completion <{u}>...".format(j=job_name, b=build_no, u=build_url))
    while True:
        buildinfo = j.get_build_info(job_name, build_no)
        if not buildinfo['building']:
            # job is not still building
            duration = datetime.timedelta(seconds=(buildinfo['duration'] / 1000))
            if pushover:
                notify_pushover(buildinfo['result'], job_name, build_no, duration, build_url)
            if buildinfo['result'] == "SUCCESS":
                print("SUCCESS for {j} #{b} in {d} <{bu}>".format(j=job_name, b=build_no, bu=build_url, d=duration))
                raise SystemExit(0)
            print("{r}: {j} #{b} failed in {d}".format(j=job_name, b=build_no, r=buildinfo['result'], d=duration))
            raise SystemExit(1)
        else:
            duration = datetime.datetime.now() - datetime.datetime.fromtimestamp(buildinfo['timestamp'] / 1000)
            print("still running ({d})...".format(d=duration))
        time.sleep(sleeptime)
Exemplo n.º 3
0
Arquivo: jks.py Projeto: Eylaine/ast
class JenkinsInfo:

    config = Config.get_jenkins_config()

    def __init__(self):
        self.jks = Jenkins(url=self.config["url"],
                           username=self.config["user"],
                           password=self.config["pwd"])
        self.job_name = self.config["job_name"]

    def get_info(self):
        result = dict()

        last_success_info = self.jks.get_job_info(self.job_name)["lastSuccessfulBuild"]
        url = last_success_info["url"]
        last_num = last_success_info["number"]
        # result["last_num"] = last_num
        build_info = self.jks.get_build_info(self.job_name, last_num)
        artifact = build_info["artifacts"][0]
        apk_name = artifact["fileName"]
        result["apk_name"] = apk_name
        relative_path = artifact["relativePath"]

        download_url = f"{url}artifact/{relative_path}"
        result["download_url"] = download_url

        return result
Exemplo n.º 4
0
 def _upsert_jenkins_job(server: Jenkins, full_job_name: str, xml_job_config: str):
     if server.job_exists(full_job_name):
         job = server.get_job_info(full_job_name)
     else:
         print(f'Jenkins job {full_job_name} doesn''t exist.')
         job = None
     config_xml_string = canonicalize_jenkins_xml(xml_job_config)
     if job is None and writeback:
         print(f'Creating new job {full_job_name}')
         try:
             server.create_job(full_job_name, config_xml_string)
         except JenkinsException as e:
             print(f'Failed creating job:\n{e}')
     elif job is not None:
         current_xml_string = canonicalize_jenkins_xml(server.get_job_config(full_job_name))
         diffs = diff_files(BytesIO(bytearray(current_xml_string, encoding='utf-8')),
                            BytesIO(bytearray(config_xml_string, encoding='utf-8')))
         if len(diffs) > 0:
             print(f'Jenkins job {full_job_name} needs update')
             if writeback:
                 print(json.dumps(diffs, indent=4))
                 if input(f'Are you sure you want to update configuration for {full_job_name} (y/n) ? ') == 'y':
                     print(f'Updating job configuration for {full_job_name}')
                     try:
                         server.reconfig_job(full_job_name, config_xml_string)
                     except JenkinsException as e:
                         print(f'Failed updating job:\n{e}')
Exemplo n.º 5
0
class TaskBuilder:

  def __init__(self, jenkinsURL):
    self.j = Jenkins(jenkinsURL)
    self.jobName = ""
    #with open("config.xml") as file:
    with open("./builds/config/job/config.xml") as file:
      self.templateConfig = file.read()
    self.template = Template(unicode(self.templateConfig))

  def set_new_config(self, **params):
    self.newConfig = self.template.render(repos=params['repos'], description=params['repos'])

  def add_build(self, **params):
    self.set_job_name(**params)
    self.set_new_config(**params)

    if self.j.job_exists(self.jobName):
      self.do_build(**params)
    else:
      
      self.j.create_job(self.jobName, self.newConfig)
      self.do_build(**params)

  def do_build(self, **params):
    self.set_job_name(**params)
    self.set_new_config(**params)

    self.j.enable_job(self.jobName)
    self.j.build_job(self.jobName, {'branch': params['branch'], 'version': params['version'], 'author': params['author'], \
      'styleguide_repo': params['styleguide_repo'], 'styleguide_branch': params['styleguide_branch'], 'sidecar_repo': params['sidecar_repo'], \
      'sidecar_branch': params['sidecar_branch'], 'package_list': params['package_list'], 'upgrade_package': params['upgrade_package']})
  
  def set_job_name(self,**params):
    buildUtil = BuildUtil()
    self.jobName = buildUtil.get_job_name(repos=params['repos'])

  def get_build_status(self, jobName):
    #job_info = self.j.get_job_info(self.jobName)
    #return build_status
    color_status = {"aborted":"Aborted",  "red": "Failed", "blue": "Succcess"}
    if jobName == "":
      print "Have to specify job name"
      return False
    else:
      if self.j.job_exists(jobName):
        #Job exist in the job list
        job_info = self.j.get_job_info(jobName)

        if color_status.has_key(job_info['color']):
          return color_status[job_info['color']]
        else:
          return 'Running'
      else:
        print "Have to specify a validate job name"
        return False

  def get_job_name(self):
    return self.jobName
Exemplo n.º 6
0
class JenkinsAPI(object):
    def __init__(self):
        self.__server = Jenkins(settings.JENKINS.get('URI'))

    def get_all_jobs(self):
        return self.__server.get_all_jobs()

    def get_next_build_number(self, name):
        return self.__server.get_job_info(name)['nextBuildNumber']

    def build_job(self, name, parameters=None):
        return self.__server.build_job(name=name, parameters=parameters)

    def get_build_info(self, name, build_number):
        try:
            return self.__server.get_build_info(name, build_number)
        except Exception as e:
            logger.exception(e)
            return None

    def get_build_console_output(self, name, number):
        try:
            return self.__server.get_build_console_output(name, number)
        except JenkinsException as e:
            logger.exception(e)
            return None

    def download_package(self, package_url, name, build_number):
        URI = settings.JENKINS.get('URI')
        download_url = '{}/job/{}/{}/artifact/{}'.format(
            URI, name, build_number, package_url)
        logger.debug(download_url)
        local_filename = download_url.split('/')[-1]
        code_path = os.path.join(settings.DEPLOY.get('CODE_PATH'), 'packages')
        local_full_filename = os.path.join(code_path, local_filename)

        # with requests.get(url, stream=True,
        # auth=HTTPBasicAuth("zhoujinliang", "117c911a35acf51e428e29f3ccb363f53f")) as r:
        with requests.get(download_url, stream=True) as r:
            r.raise_for_status()
            with open(local_full_filename, 'wb') as f:
                for chunk in r.iter_content(chunk_size=8192):
                    if chunk:  # filter out keep-alive new chunks
                        f.write(chunk)
        return local_full_filename

    def cancel_build(self, name, queue_id, build_number):
        try:
            self.__server.cancel_queue(queue_id)
            self.__server.stop_build(name, build_number)
        except Exception as e:
            logger.error(e)

    def test(self):
        return self.__server.cancel_queue(3590)
        # # return self.__server.stop_build('devops', 98)
        return self.__server.get_queue_info()
Exemplo n.º 7
0
def main(build_url, sleeptime=15, pushover=False, user=None, password=None):
    if pushover and not have_pushover:
        raise SystemExit(
            "ERROR: to use pushover notifications, please `pip install python-pushover` and configure it."
        )
    job_name, build_no = get_job_name_and_build_number(build_url)
    logger.info("Job: %s", job_name)
    logger.info("Build Number: %s", build_no)
    jenkins_url = get_jenkins_base_url(build_url)
    logger.debug("Connecting to Jenkins...")

    if user is not None:
        logger.debug("Connecting to Jenkins as user %s ...", user)
        j = Jenkins(jenkins_url, user, password)
    else:
        logger.debug("Connecting to Jenkins anonymously...")
        j = Jenkins(jenkins_url)
    logger.debug("Connected.")

    if build_no is None:
        jobinfo = j.get_job_info(job_name)
        build_no = jobinfo['nextBuildNumber'] - 1
        logger.info("Using latest build, #{b}".format(b=build_no))
    build_url = get_formal_build_url(jenkins_url, job_name, build_no)
    print("Watching job {j} #{b} until completion <{u}>...".format(
        j=job_name, b=build_no, u=build_url))
    while True:
        logger.debug("Getting build info...")
        buildinfo = j.get_build_info(job_name, build_no)
        if not buildinfo['building']:
            # job is not still building
            duration = datetime.timedelta(seconds=(buildinfo['duration'] /
                                                   1000))
            if pushover:
                notify_pushover(buildinfo['result'], job_name, build_no,
                                duration, build_url)
            if buildinfo['result'] == "SUCCESS":
                print("SUCCESS for {j} #{b} in {d} <{bu}>".format(j=job_name,
                                                                  b=build_no,
                                                                  bu=build_url,
                                                                  d=duration))
                raise SystemExit(0)
            print("{r}: {j} #{b} failed in {d}".format(j=job_name,
                                                       b=build_no,
                                                       r=buildinfo['result'],
                                                       d=duration))
            raise SystemExit(1)
        else:
            duration = datetime.datetime.now(
            ) - datetime.datetime.fromtimestamp(buildinfo['timestamp'] / 1000)
            print("still running ({d})...".format(d=duration))
        time.sleep(sleeptime)
Exemplo n.º 8
0
class JenkinsBot(BotPlugin):
    def __init__(self):
        self.jenkins = Jenkins(JENKINS_URL, JENKINS_USERNAME, JENKINS_PASSWORD)

    @botcmd
    def jenkins_list(self, mess, args):
        """List all jobs, optionally filter them using a search term."""
        self.send(mess.getFrom(),
                  u'/me is getting the list of jobs from Jenkins... ',
                  message_type=mess.getType())

        search_term = args.strip().lower()
        jobs = [
            job for job in self.jenkins.get_jobs()
            if search_term.lower() in job['name'].lower()
        ]

        return self.format_jobs(jobs)

    @botcmd
    def jenkins_running(self, mess, args):
        """List all running jobs."""
        self.send(mess.getFrom(),
                  u'/me is getting the list of jobs from Jenkins... ',
                  message_type=mess.getType())

        jobs = [
            job for job in self.jenkins.get_jobs() if 'anime' in job['color']
        ]

        return self.format_running_jobs(jobs)

    def format_jobs(self, jobs):
        if len(jobs) == 0:
            return u'No jobs found.'

        max_length = max([len(job['name']) for job in jobs])
        return '\n'.join([
            '%s (%s)' % (job['name'].ljust(max_length), job['url'])
            for job in jobs
        ]).strip()

    def format_running_jobs(self, jobs):
        if len(jobs) == 0:
            return u'No running jobs.'

        jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs]
        return '\n\n'.join([
            '%s (%s)\n%s' % (job['name'], job['lastBuild']['url'],
                             job['healthReport'][0]['description'])
            for job in jobs_info
        ]).strip()
Exemplo n.º 9
0
def errors(job_name, jenkins_username, jenkins_token):
    """Console script for jenkins_triage."""
    global server
    #    job_name = 'enterprise_pe-acceptance-tests_integration-system_pe_full-upgrade_weekend_2016.4.x' # 'enterprise_pe-orchestrator_intn-van-sys-pez-multi_2016.4.x-2016.4.x' # 'enterprise_pe-modules-vanagon-suite_intn-van-sys-pez-multi_daily-pe-modules-2016.4.x'
    server = Jenkins(
        'https://cinext-jenkinsmaster-enterprise-prod-1.delivery.puppetlabs.net',
        username=jenkins_username,
        password=jenkins_token)
    info = server.get_job_info(job_name)
    builds = [
        server.get_build_info(job_name, build['number'])
        for build in info['builds']
    ]
    failed_build_numbers = [b for b in builds if b['result'] == 'FAILURE']
    last_job_errors = None

    counts = defaultdict(int)
    similar = set()
    for build in failed_build_numbers:
        output = server.get_build_console_output(job_name, build['number'])
        finder = get_strategy(output)
        errors = finder(output)
        print "Errors: {}".format(errors)
        if last_job_errors:
            seq = difflib.SequenceMatcher(a=last_job_errors, b=errors)
            if seq.ratio() == 1.0:
                counts['exact'] += 1
            if seq.ratio() >= 0.7 and seq.ratio() < 1.0:
                counts['similar'] += 1
                similar.append(errors)
        else:
            last_job_errors = errors

    if last_job_errors:
        click.echo('Last job errors were:')
        click.echo('\t{}'.format('\n\t'.join(last_job_errors)))

    if last_job_errors and 'exact' in counts:
        click.echo(
            'There were {} jobs that failed with errors exactly the same as the last failed job:'
            .format(counts['exact']))
        click.echo('\t{}'.format('\n\t'.join(last_job_errors)))

    if last_job_errors and 'similar' in counts:
        click.echo(
            'There were {} jobs that failed with experienced similar errors as the last failed job:'
            .format(counts['exact']))
        click.echo('\t{}'.format('\n\t'.join(last_job_errors)))
        for s in similar:
            click.echo('Additional Failed Job:')
            click.echo('\t{}'.format('\n\t'.join(s)))
Exemplo n.º 10
0
def main():
    parser = ArgumentParser()
    parser.add_argument('-j', '--jobname', type=str, default=None)
    parser.add_argument('-n', '--dry_run', action='store_true')
    parser.add_argument('-d', '--distro', type=str,
                        default='all')  # maybe implement an 'all' logic?
    parser.add_argument('-r', '--release', type=str, default='leste')

    args = parser.parse_args()

    if args.release not in DEFAULT_RELEASES:
        print('Release unsupported. Use something from %s' %
              DEFAULT_RELEASES.keys())
        sys.exit(1)

    if args.distro not in DEFAULT_RELEASES[args.release]:
        print('Distro unsupported. Use something from %s' %
              DEFAULT_RELEASES[args.release])
        sys.exit(1)

    release = args.release
    distribution = args.distro

    japi = Jenkins(jenkins_host, username=jenkins_user, password=jenkins_pass)

    jobs = get_jobs()

    if args.dry_run:
        print('Would start:', args.jobname)
        sys.exit(0)

    if args.jobname not in jobs:
        print('Job does not exist in config')
        sys.exit(1)

    # Racy, but whatever
    nextjob = japi.get_job_info('%s-source' % args.jobname)['nextBuildNumber']
    job_no = japi.build_job('%s-source' % args.jobname, {
        'release': release,
        'distribution': distribution
    })
    print('Build number:', nextjob)
Exemplo n.º 11
0
def main(build_url, sleeptime=15, pushover=False, user=None, password=None):
    if pushover and not have_pushover:
        raise SystemExit("ERROR: to use pushover notifications, please `pip install python-pushover` and configure it.")
    job_name, build_no = get_job_name_and_build_number(build_url)
    logger.info("Job: %s", job_name)
    logger.info("Build Number: %s", build_no)
    jenkins_url = get_jenkins_base_url(build_url)
    logger.debug("Connecting to Jenkins...")

    if user is not None:
        logger.debug("Connecting to Jenkins as user %s ...", user)
        j = Jenkins(jenkins_url, user, password)
    else:
        logger.debug("Connecting to Jenkins anonymously...")
        j = Jenkins(jenkins_url)
    logger.debug("Connected.")

    if build_no is None:
        jobinfo = j.get_job_info(job_name)
        build_no = jobinfo['nextBuildNumber'] - 1
        logger.info("Using latest build, #{b}".format(b=build_no))
    build_url = get_formal_build_url(jenkins_url, job_name, build_no)
    print("Watching job {j} #{b} until completion <{u}>...".format(j=job_name, b=build_no, u=build_url))
    while True:
        logger.debug("Getting build info...")
        buildinfo = j.get_build_info(job_name, build_no)
        if not buildinfo['building']:
            # job is not still building
            duration = datetime.timedelta(seconds=(buildinfo['duration'] / 1000))
            if pushover:
                notify_pushover(buildinfo['result'], job_name, build_no, duration, build_url)
            if buildinfo['result'] == "SUCCESS":
                print("SUCCESS for {j} #{b} in {d} <{bu}>".format(j=job_name, b=build_no, bu=build_url, d=duration))
                raise SystemExit(0)
            print("{r}: {j} #{b} failed in {d}".format(j=job_name, b=build_no, r=buildinfo['result'], d=duration))
            raise SystemExit(1)
        else:
            duration = datetime.datetime.now() - datetime.datetime.fromtimestamp(buildinfo['timestamp'] / 1000)
            print("still running ({d})...".format(d=duration))
        time.sleep(sleeptime)
Exemplo n.º 12
0
class JenkinsControl(object):
    war=pjoin(here, 'tmp/jenkins.war')
    cli=pjoin(here, 'tmp/jenkins-cli.jar')
    home=pjoin(here, 'tmp/jenkins')

    def __init__(self, addr='127.0.0.1:60888', cport='60887'):
        self.addr, self.port = addr.split(':')
        self.url = 'http://%s' % addr
        self.py = Jenkins(self.url)

    def start_server(self):
        cmd = pjoin(here, './bin/start-jenkins.sh 1>/dev/null 2>&1')
        env={'JENKINS_HOME'  : self.home,
             'JENKINS_PORT'  : self.port,
             'JENKINS_CPORT' : self.cport,
             'JENKINS_ADDR'  : self.addr}
        check_call(cmd, shell=True, env=env)

    def shutdown_server(self):
        cmd = 'echo 0 | nc %s %s' % (self.addr, self.cport)
        check_call(cmd, shell=True)

    def clean_home(self):
        rmtree(self.home)

    def createjob(self, name, configxml_fn):
        self.py.create_job(name, open(configxml_fn).read())

    def getjobs(self):
        return {i['name'] : i for i in self.py.get_jobs()}

    def enabled(self, name):
       return self.py.get_job_info(name)['buildable']

    def job_etree(self, job):
        res = self.py.get_job_config(job)
        res = etree.fromstring(res)
        return res
Exemplo n.º 13
0
class JenkinsBot(BotPlugin):

    def __init__(self):
        self.jenkins = Jenkins(JENKINS_URL, JENKINS_USERNAME, JENKINS_PASSWORD)

    @botcmd
    def jenkins_list(self, mess, args):
        """List all jobs, optionally filter them using a search term."""
        self.send(mess.getFrom(), u'/me is getting the list of jobs from Jenkins... ', message_type=mess.getType())

        search_term = args.strip().lower()
        jobs = [job for job in self.jenkins.get_jobs() if search_term.lower() in job['name'].lower()]

        return self.format_jobs(jobs)

    @botcmd
    def jenkins_running(self, mess, args):
        """List all running jobs."""
        self.send(mess.getFrom(), u'/me is getting the list of jobs from Jenkins... ', message_type=mess.getType())

        jobs = [job for job in self.jenkins.get_jobs() if 'anime' in job['color']]

        return self.format_running_jobs(jobs)

    def format_jobs(self, jobs):
        if len(jobs) == 0:
            return u'No jobs found.'

        max_length = max([len(job['name']) for job in jobs])
        return '\n'.join(['%s (%s)' % (job['name'].ljust(max_length), job['url']) for job in jobs]).strip()

    def format_running_jobs(self, jobs):
        if len(jobs) == 0:
            return u'No running jobs.'

        jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs]
        return '\n\n'.join(['%s (%s)\n%s' % (job['name'], job['lastBuild']['url'], job['healthReport'][0]['description']) for job in jobs_info]).strip()
from jenkins import Jenkins
import pprint

result_to_color = {
    'SUCCESS': 'G',
    'UNSTABLE': 'Y',
    'FAILURE': 'R',
    'BUILDING': 'B'
}

SERVER_URL = 'http://ci.attentec.se'
JOB_NAME = 'Hacka-Traffic-Light'

jenkins = Jenkins(SERVER_URL)

jobs = jenkins.get_job_info(JOB_NAME, 0, False)
last_build = jobs["lastBuild"]
last_build_number = last_build["number"]

NrOfStatuses = min(10, last_build_number)
results = [None] * NrOfStatuses

for i in range(len(results)):
    build_info = jenkins.get_build_info(JOB_NAME, last_build_number - i)
    if build_info["result"] is None:
        results[i] = 'BUILDING'
    else:
        results[i] = build_info["result"]
    print("build: {} result: {}".format(last_build_number - i,
                                        result_to_color[results[i]]))
Exemplo n.º 15
0
class JenkinsTrigger(object):
    """
    A class to trigger builds on Jenkins and print the results.

    :param token: The token we need to trigger the build. If you do not have this token, ask in IRC.
    """
    def __init__(self, username, password, can_use_colour):
        """
        Create the JenkinsTrigger instance.
        """
        self.jobs = {}
        self.can_use_colour = can_use_colour and not os.name.startswith('nt')
        self.repo_name = get_repo_name()
        self.server = Jenkins(JENKINS_URL,
                              username=username,
                              password=password)

    def fetch_jobs(self):
        """
        Get the job info for all the jobs
        """
        for job_name in OpenLPJobs.Jobs:
            job_info = self.server.get_job_info(job_name)
            self.jobs[job_name] = job_info
            self.jobs[job_name][
                'nextBuildUrl'] = '{url}{nextBuildNumber}/'.format(**job_info)

    def trigger_build(self):
        """
        Ask our jenkins server to build the "Branch-01-Pull" job.
        """
        bzr = Popen(('bzr', 'whoami'), stdout=PIPE, stderr=PIPE)
        raw_output, error = bzr.communicate()
        # We just want the name (not the email).
        name = ' '.join(raw_output.decode().split()[:-1])
        cause = 'Build triggered by %s (%s)' % (name, self.repo_name)
        self.fetch_jobs()
        self.server.build_job(OpenLPJobs.Branch_Pull, {
            'BRANCH_NAME': self.repo_name,
            'cause': cause
        })

    def print_output(self, can_continue=False):
        """
        Print the status information of the build triggered.
        """
        print('Add this to your merge proposal:')
        print('-' * 80)
        bzr = Popen(('bzr', 'revno'), stdout=PIPE, stderr=PIPE)
        raw_output, error = bzr.communicate()
        revno = raw_output.decode().strip()
        print('%s (revision %s)' % (get_repo_name(), revno))

        failed_builds = []
        for job in OpenLPJobs.Jobs:
            if not self.__print_build_info(job):
                if self.current_build:
                    failed_builds.append(
                        (self.current_build['fullDisplayName'],
                         self.current_build['url']))
                if not can_continue:
                    print('Stopping after failure')
                    break
        print('')
        if failed_builds:
            print('Failed builds:')
            for build_name, url in failed_builds:
                print(' - {}: {}console'.format(build_name, url))
        else:
            print('All builds passed')

    def open_browser(self):
        """
        Opens the browser.
        """
        url = self.jenkins_instance.job(OpenLPJobs.Branch_Pull).info['url']
        # Open the url
        Popen(('xdg-open', url), stderr=PIPE)

    def _get_build_info(self, job_name, build_number):
        """
        Get the build info from the server. This method will check the queue and wait for the build.
        """
        queue_info = self.server.get_queue_info()
        tries = 0
        loop_count = 100
        while queue_info and tries < loop_count:
            tries += 1
            time.sleep(1)
            queue_info = self.server.get_queue_info()
        if tries >= loop_count:
            raise Exception(
                'Build has not started yet, it may be stuck in the queue.')
        return self.server.get_build_info(job_name, build_number)

    def __print_build_info(self, job_name):
        """
        This helper method prints the job information of the given ``job_name``

        :param job_name: The name of the job we want the information from. For example *Branch-01-Pull*. Use the class
         variables from the :class:`OpenLPJobs` class.
        """
        job = self.jobs[job_name]
        print('{:<70} [WAITING]'.format(job['nextBuildUrl']),
              end='',
              flush=True)
        self.current_build = self._get_build_info(job_name,
                                                  job['nextBuildNumber'])
        print('\b\b\b\b\b\b\b\b\b[RUNNING]', end='', flush=True)
        while self.current_build['building'] is True:
            time.sleep(0.5)
            self.current_build = self.server.get_build_info(
                job_name, job['nextBuildNumber'])
        result_string = self.current_build['result']
        is_success = result_string == 'SUCCESS'
        if self.can_use_colour:
            if is_success:
                # Make 'SUCCESS' green.
                result_string = '{}{}{}'.format(Colour.GREEN_START,
                                                result_string,
                                                Colour.GREEN_END)
            else:
                # Make 'FAILURE' red.
                result_string = '{}{}{}'.format(Colour.RED_START,
                                                result_string, Colour.RED_END)
        print('\b\b\b\b\b\b\b\b\b[{:>7}]'.format(result_string))
        return is_success
Exemplo n.º 16
0
def gather(job_name, start_delimiter, end_delimiter, jenkins_username,
           jenkins_token):
    global server
    #    job_name = 'enterprise_pe-acceptance-tests_integration-system_pe_full-upgrade_weekend_2016.4.x' # 'enterprise_pe-orchestrator_intn-van-sys-pez-multi_2016.4.x-2016.4.x' # 'enterprise_pe-modules-vanagon-suite_intn-van-sys-pez-multi_daily-pe-modules-2016.4.x'
    server = Jenkins(
        'https://cinext-jenkinsmaster-enterprise-prod-1.delivery.puppetlabs.net',
        username=jenkins_username,
        password=jenkins_token)
    info = server.get_job_info(job_name)
    builds = [
        server.get_build_info(job_name, build['number'])
        for build in info['builds']
    ]
    last_job_check_lines = None
    counts = defaultdict(int)
    similar = set()
    for build in builds:
        output = server.get_build_console_output(job_name, build['number'])
        #        print output
        try:
            req = jenkins.requests.Request(
                'GET',
                'https://cinext-jenkinsmaster-enterprise-prod-1.delivery.puppetlabs.net/view/__experimental/job/experimental_pe-acceptance-tests_integration-system_pe_full_nightly_2018.1.x/{}/LAYOUT=ubuntu1604-64mcd-64f-32f,LEGACY_AGENT_VERSION=NONE,PLATFORM=NONE,SCM_BRANCH=2018.1.x,UPGRADE_FROM=NONE,UPGRADE_TO_VERSION=NONE,label=beaker/testReport/(root)/acceptance_tests_01_post_install_tests/idempotent_rb'
                .format(build['number']))
            html_doc = server.jenkins_open(req)
        except:
            continue

        soup = BeautifulSoup(html_doc, 'html.parser')
        #        output = soup.pre.get_text()

        finder = get_strategy(output,
                              start_delimiter=start_delimiter,
                              end_delimiter=end_delimiter)
        found_lines = finder(output,
                             job_name,
                             build['number'],
                             start_delimiter=start_delimiter,
                             end_delimiter=end_delimiter)

        print("Found lines: ".format(found_lines))
        if last_job_check_lines:
            seq = difflib.SequenceMatcher(a=last_job_check_lines,
                                          b=found_lines)

            if seq.ratio() == 1.0:
                counts['exact'] += 1
            if seq.ratio() >= 0.7 and seq.ratio() < 1.0:
                counts['similar'] += 1
                similar.append(found_lines)
        else:
            last_job_check_lines = found_lines

    if last_job_check_lines:
        click.echo('Last job check_lines were:')
        click.echo('\t{}'.format('\n\t'.join(last_job_check_lines)))

    if last_job_check_lines and 'exact' in counts:
        click.echo(
            'There were {} jobs that failed with check_lines exactly the same as the last failed job:'
            .format(counts['exact']))
        click.echo('\t{}'.format('\n\t'.join(last_job_check_lines)))

    if last_job_check_lines and 'similar' in counts:
        click.echo(
            'There were {} jobs that failed with experienced similar check_lines as the last failed job:'
            .format(counts['exact']))
        click.echo('\t{}'.format('\n\t'.join(last_job_check_lines)))
        for s in similar:
            click.echo('Additional Failed Job:')
            click.echo('\t{}'.format('\n\t'.join(s)))
Exemplo n.º 17
0
class JenkinsBot(BotPlugin):

    def connect_to_jenkins(self):
        self.jenkins = Jenkins(JENKINS_URL, username=JENKINS_USERNAME, password=JENKINS_PASSWORD)

    @botcmd
    def jenkins_list(self, mess, args):
        """List all jobs, optionally filter them using a search term."""
        self.connect_to_jenkins()

        search_term = args.strip().lower()
        jobs = self.search_job(search_term)
        
        return self.format_jobs(jobs)


    @botcmd
    def jenkins_running(self, mess, args):
        """List all running jobs."""
        self.connect_to_jenkins()

        jobs = [job for job in self.jenkins.get_jobs() if 'anime' in job['color']]

        return self.format_running_jobs(jobs)


    @botcmd
    def jenkins_param(self, mess, args):
        """List Parameters for a given job."""
        self.connect_to_jenkins()
        
        if len(args) == 0:
            return u'What Job would you like the parameters for?'
        if len(args.split()) > 1:
            return u'Please enter only one Job Name'

        if self.jenkins.get_job_info(args)['actions'][0] == {}:
            job_param = self.jenkins.get_job_info(args)['actions'][1]['parameterDefinitions']
        else:
            job_param = self.jenkins.get_job_info(args)['actions'][0]['parameterDefinitions']

        return self.format_params(job_param)


    @botcmd(split_args_with=None)
    def jenkins_build(self, mess, args):
        """Build a Jenkins Job with the given parameters
        Example: !jenkins build test_project FOO:bar
        """
        self.connect_to_jenkins()

        if len(args) == 0:
            return u'What job would you like to build?'

        parameters = self.build_parameters(args[1:])
        self.jenkins.build_job(args[0], parameters)
        running_job = self.search_job(args[0])
        
        return 'Your job should begin shortly: {0}'.format(self.format_jobs(running_job))


    def search_job(self, search_term):
        return [job for job in self.jenkins.get_jobs() if search_term.lower() in job['name'].lower()]


    def format_jobs(self, jobs):
        if len(jobs) == 0:
            return u'No jobs found.'

        max_length = max([len(job['name']) for job in jobs])
        return '\n'.join(['%s (%s)' % (job['name'].ljust(max_length), job['url']) for job in jobs]).strip()


    def format_running_jobs(self, jobs):
        if len(jobs) == 0:
            return u'No running jobs.'

        jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs]
        return '\n\n'.join(['%s (%s)\n%s' % (job['name'], job['lastBuild']['url'], job['healthReport'][0]['description']) for job in jobs_info]).strip()


    def format_params(self, job):
        parameters = ''

        for param in range (0, len(job)):
            parameters = parameters + ("Type: {0}\nDescription: {1}\nDefault Value: {2}\nParameter Name: {3}\n_\n"
                .format(job[param]['type'], job[param]['description'], str(job[param]['defaultParameterValue']['value']), job[param]['name']))

        return parameters


    def build_parameters(self, params):
        if len(params) == 0:
            return ast.literal_eval("{'':''}")

        parameters_list = "{'"

        for counter, param in enumerate(params):
            param = param.split(':')
            if counter < len(params) - 1:
                parameters_list = parameters_list + param[0] + "': '" + param[1] + "', '"
            else:
                parameters_list = parameters_list + param[0] + "': '" + param[1] + "'"

        parameters_list = parameters_list + '}'

        return ast.literal_eval(parameters_list)
Exemplo n.º 18
0
class JenkinsBot(BotPlugin):
    """JenkinsBot is an Err plugin to manage Jenkins CI jobs from your chat platform like Slack."""
    def __init__(self, bot):
        self.jenkins = Jenkins(JENKINS_URL, JENKINS_USERNAME, JENKINS_PASSWORD)
        super().__init__(bot)

    @botcmd(split_args_with=None)
    def jenkins_build(self, msg, args):
        """Build the job specified by jobName. You can add params!"""

        # Params are passed like "key1=value1 key2=value2"
        params = {}
        try:
            for arg in args[1:]:
                params[arg.split('=', 1)[0]] = arg.split('=', 1)[1]
        except IndexError:
            return "I don't like that params! Try with this format: key1=value1 key2=value2..."

        try:
            self.jenkins.build_job(args[0].strip(), params)
        except NotFoundException:
            return "Sorry, I can't find the job. Typo maybe?"

        return ' '.join([
            "The job", args[0].strip(),
            "has been sent to the queue to be built."
        ])

    @botcmd
    def jenkins_cancel(self, msg, args):
        """Cancel a job in the queue by jobId."""

        try:
            self.jenkins.cancel_queue(args.strip())
        except NotFoundException:
            return "Sorry, I can't find the job. Maybe the ID does not exist."

        return "Job canceled from the queue."

    @botcmd
    def jenkins_list(self, msg, args):
        """List Jenkins jobs. You can filter with strings."""

        self.send(msg.to, "I'm getting the jobs list from Jenkins...")

        search_term = args.strip().lower()
        jobs = [
            job for job in self.jenkins.get_jobs()
            if search_term.lower() in job['name'].lower()
        ]

        return self.format_jobs(jobs)

    @botcmd
    def jenkins_describe(self, msg, args):
        """Describe the job specified by jobName."""

        try:
            job = self.jenkins.get_job_info(args.strip())
        except NotFoundException:
            return "Sorry, I can't find the job. Typo maybe?"

        return ''.join([
            'Name: ', job['name'], '\n', 'URL: ', job['url'], '\n',
            'Description: ',
            'None' if job['description'] is None else job['description'], '\n',
            'Next Build Number: ',
            str('None'
                if job['nextBuildNumber'] is None else job['nextBuildNumber']),
            '\n', 'Last Successful Build Number: ',
            str('None' if job['lastBuild'] is None else job['lastBuild']
                ['number']), '\n', 'Last Successful Build URL: ',
            'None' if job['lastBuild'] is None else job['lastBuild']['url'],
            '\n'
        ])

    @botcmd
    def jenkins_running(self, msg, args):
        """List running jobs."""

        self.send(msg.to, "I will ask for the current running builds list!")

        jobs = self.jenkins.get_running_builds()

        return self.format_running_jobs(jobs)

    @botcmd(split_args_with=None)
    def jenkins_stop(self, msg, args):
        """Stop the building job specified by jobName and jobNumber."""

        try:
            int(args[1].strip())
        except ValueError:
            return "You have to specify the jobNumber: \"!jenkins stop <jobName> <jobNumber>"

        try:
            self.jenkins.stop_build(args[0].strip(), int(args[1].strip()))
        except NotFoundException:
            return "Sorry, I can't find the job. Typo maybe?"

        return ' '.join(["The job", args[0].strip(), "has been stopped."])

    @botcmd
    def jenkins_queue(self, msg, args):
        """List jobs in queue."""

        self.send(msg.to, "Getting the job queue...")

        jobs = self.jenkins.get_queue_info()

        return self.format_queue_jobs(jobs)

    def format_jobs(self, jobs):
        """Format jobs list"""

        if len(jobs) == 0:
            return "I haven't found any job."

        max_length = max([len(job['name']) for job in jobs])
        return '\n'.join([
            '%s (%s)' % (job['name'].ljust(max_length), job['url'])
            for job in jobs
        ]).strip()

    def format_queue_jobs(self, jobs):
        """Format queue jobs list"""

        if len(jobs) == 0:
            return "It seems that there is not jobs in queue."

        return '\n'.join([
            '%s - %s (%s)' %
            (str(job['id']), job['task']['name'], job['task']['url'])
            for job in jobs
        ]).strip()

    def format_running_jobs(self, jobs):
        """Format running jobs list"""

        if len(jobs) == 0:
            return "There is no running jobs!"

        return '\n'.join([
            '%s - %s (%s) - %s' %
            (str(job['number']), job['name'], job['url'], job['executor'])
            for job in jobs
        ]).strip()
Exemplo n.º 19
0
class JenkinsTools(object):
    """
    Jenkins操作工具类
    """
    def __init__(self, url, username, password):
        """
        初始化Jenkins连接信息
        :param url: Jenkins地址
        :param username: 登录用户名
        :param password: 登录密码
        """
        try:
            self.session = Jenkins(url=url,
                                   username=username,
                                   password=password)
        except Exception:
            logger.exception('初始化Jenkins连接过程中发生异常,请检查!')

    @property
    def get_session(self):
        """
        返回Jenkins会话
        :return:
        """
        return self.session

    def get_job_info(self, job_name):
        """
        获取构建项目信息
        :param job_name: 构建项目名称
        :return:
        """
        try:
            if self.session.job_exists(name=job_name):
                info = self.session.get_job_info(name=job_name)
                return info
            else:
                logger.warning(
                    '[WARNING]: Jenkins构建项目"{}"并不存在,请检查!'.format(job_name))
                sys.exit(1)
        except Exception:
            logger.exception('查看Jenkins构建项目"{}"过程中发生异常,请检查!'.format(job_name))

    def get_job_info_by_regex(self, pattern):
        """
        正则表达式方式获取构建项目信息
        :param pattern: 构建项目名称(正则表达式)
        :return:
        """
        try:
            info_regex = self.session.get_job_info_regex(pattern=pattern)
            return info_regex
        except Exception:
            logger.exception('通过正则表达式"{}"查看匹配构建项目过程中发生异常,请检查!'.format(pattern))

    def get_job_build_info(self, job_name, build_number):
        """
        通过构建项目名称及构建任务ID查看构建信息
        :param job_name: 构建项目名称
        :param build_number: 构建ID
        :return:
        """
        try:
            result = self.session.get_build_info(name=job_name,
                                                 number=build_number)
            return result
        except Exception:
            logger.exception('通过构建项目名称"{}"和构建ID"{}"查看构建信息过程中发生异常,请检查!'.format(
                job_name, build_number))

    def rebase_build_info(self, job_name):
        """
        获取指定项目名称的自定义构建信息
        :param job_name: 构建项目名称
        :return: 构建信息自定义响应体
        """
        response_list = []
        try:
            job_set = self.get_job_info(job_name)
            if job_set['lastBuild'] is not None:
                response_list.append(
                    dict(
                        ActionJob=job_set['displayName'],
                        LastNumber=job_set['lastBuild']['number'],
                        Building=self.get_job_build_info(
                            job_set['displayName'],
                            job_set['lastBuild']['number'])['building'],
                        Result=self.get_job_build_info(
                            job_set['displayName'],
                            job_set['lastBuild']['number'])['result'],
                        Time=trans_timestamp(
                            self.get_job_build_info(
                                job_set['displayName'],
                                job_set['lastBuild']['number'])['timestamp'])))
            else:
                response_list.append(
                    dict(ActionJob=job_set['displayName'],
                         LastBuild="No latest build job info now."))
            return response_list
        except Exception:
            logger.exception(
                '通过构建项目名称"{}"查看其自定义构建信息过程中发生异常,请检查!'.format(job_name))

    def rebase_build_info_by_regex(self, pattern):
        """
        获取匹配正则表达式项目名称的自定义构建信息
        :param pattern: 构建项目名称(正则表达式)
        :return: 构建信息自定义响应体
        """
        response_list = []
        try:
            job_set = self.get_job_info_by_regex(pattern)
            if len(job_set) != 0:
                for i in job_set:
                    if i['lastBuild'] is not None:
                        response_list.append(
                            dict(ActionJob=i['displayName'],
                                 LastNumber=i['lastBuild']['number'],
                                 Building=self.get_build_info(
                                     i['displayName'],
                                     i['lastBuild']['number'])['building'],
                                 Result=self.get_build_info(
                                     i['displayName'],
                                     i['lastBuild']['number'])['result'],
                                 Time=trans_timestamp(
                                     self.get_build_info(
                                         i['displayName'], i['lastBuild']
                                         ['number'])['timestamp']),
                                 Operator=self.get_build_info(
                                     i['displayName'],
                                     i['lastBuild']['number'])['actions'][0]
                                 ['causes'][0]['shortDescription']))
                    else:
                        response_list.append(
                            dict(ActionJob=i['displayName'],
                                 LastBuild="No latest build job info now."))
            return response_list
        except re.error:
            return "invalid pattern"
        except Exception:
            logger.exception(
                '通过正则表达式"{}"查看匹配项目的自定义构建信息过程中发生异常,请检查!'.format(pattern))

    def stop_job_latest_build(self, job_name):
        """
        停止匹配正则表达式的构建项目的最近构建任务
        :param job_name: 构建项目名称
        :return:
        """
        try:
            lastNumber = self.rebase_build_info(
                job_name=job_name)[0]['LastNumber']
            self.session.stop_build(name=job_name, number=lastNumber)
        except Exception:
            logger.exception(
                '停止匹配正则表达式"{}"的构建项目的最近构建任务过程中发生异常,请检查!'.format(job_name))
Exemplo n.º 20
0
class JenkinsBot(BotPlugin):
    """Basic Err integration with Jenkins CI"""

    min_err_version = '1.2.1'

    # max_err_version = '3.3.0'

    def get_configuration_template(self):
        return CONFIG_TEMPLATE

    def configure(self, configuration):
        if configuration is not None and configuration != {}:
            config = dict(chain(CONFIG_TEMPLATE.items(),
                                configuration.items()))
        else:
            config = CONFIG_TEMPLATE
        super(JenkinsBot, self).configure(config)
        return

    def check_configuration(self, configuration):
        self.log.debug(configuration)
        for c in configuration:
            if c == 'URL':
                if not validators.url(configuration['URL']):
                    raise ValidationException(
                        'JENKINS_URL is not a well formed URL')
            elif c in ['USERNAME', 'PASSWORD', 'RECEIVE_NOTIFICATION']:
                if len(configuration[c]) == 0 or not isinstance(
                        configuration[c], str):
                    raise ValidationException(
                        "{} is a required string config setting".format(c))
            elif c in ['CHATROOMS_NOTIFICATION']:
                if not isinstance(configuration[c], tuple):
                    raise ValidationException(
                        "{} should be of type tuple".format(c))
        return

    def connect_to_jenkins(self):
        """Connect to a Jenkins instance using configuration."""
        self.log.debug('Connecting to Jenkins ({0})'.format(
            self.config['URL']))
        self.jenkins = Jenkins(url=self.config['URL'],
                               username=self.config['USERNAME'],
                               password=self.config['PASSWORD'])
        return

    def broadcast(self, mess):
        """Shortcut to broadcast a message to all elligible chatrooms."""
        chatrooms = (self.config['CHATROOMS_NOTIFICATION']
                     if self.config['CHATROOMS_NOTIFICATION'] else
                     self.bot_config.CHATROOM_PRESENCE)

        for room in chatrooms:
            self.send(self.build_identifier(room),
                      mess,
                      message_type='groupchat')
        return

    @webhook(r'/jenkins/notification')
    def handle_notification(self, incoming_request):
        if not self.config['RECEIVE_NOTIFICATION']:
            return "Notification handling is disabled \
                    (JENKINS_RECEIVE_NOTIFICATION = False)"

        self.log.debug(repr(incoming_request))
        self.broadcast(self.format_notification(incoming_request))
        return "OK"

    @botcmd
    def jenkins_list(self, mess, args):
        """List all jobs, optionally filter them using a search term."""
        self.connect_to_jenkins()
        return self.format_jobs(self.jenkins.get_jobs(folder_depth=None))

    @botcmd
    def jenkins_running(self, mess, args):
        """List all running jobs."""
        self.connect_to_jenkins()

        jobs = [
            job for job in self.jenkins.get_jobs() if 'anime' in job['color']
        ]
        return self.format_running_jobs(jobs)

    @botcmd(split_args_with=None)
    def jenkins_param(self, mess, args):
        """List Parameters for a given job."""
        if len(args) == 0:
            return 'What Job would you like the parameters for?'

        self.connect_to_jenkins()

        job = self.jenkins.get_job_info(args[0])
        if job['actions'][1] != {}:
            job_param = job['actions'][1]['parameterDefinitions']
        elif job['actions'][0] != {}:
            job_param = job['actions'][0]['parameterDefinitions']
        else:
            job_param = []

        return self.format_params(job_param)

    @botcmd(split_args_with=None)
    def jenkins_build(self, mess, args):
        """Build a Jenkins Job with the given parameters
        Example: !jenkins build test_project FOO:bar
        """
        if len(args) == 0:  # No Job name
            return 'What job would you like to build?'

        self.connect_to_jenkins()
        params = self.build_parameters(args[1:])

        # Is it a parameterized job ?
        job = self.jenkins.get_job_info(args[0])
        if job['actions'][0] == {} and job['actions'][1] == {}:
            self.jenkins.build_job(args[0])
        else:
            self.jenkins.build_job(args[0], params)

        running_job = self.search_job(args[0])
        return 'Your job should begin shortly: {0}'.format(
            self.format_jobs(running_job))

    @botcmd(split_args_with=None)
    def build(self, mess, args):
        """Shortcut for jenkins_build"""
        return self.jenkins_build(mess, args)

    @botcmd(split_args_with=None)
    def jenkins_create(self, mess, args):
        """Create a Jenkins Job.
        Example: !jenkins create pipeline foo [email protected]:foo/bar.git
        """
        if len(args) < 2:  # No Job type or name
            return 'Oops, I need a type and a name for your new job.'

        if args[0] not in ('pipeline', 'multibranch'):
            return 'I\'m sorry, what type of job do you want ?'

        self.connect_to_jenkins()

        if args[0] == 'pipeline':
            self.jenkins.create_job(
                args[1],
                JENKINS_JOB_TEMPLATE_PIPELINE.format(repository=args[2]))
        elif args[0] == 'multibranch':
            return
        return

    def search_job(self, search_term):
        self.log.debug('Querying Jenkins for job "{0}"'.format(search_term))
        return [
            job for job in self.jenkins.get_jobs(folder_depth=None)
            if search_term.lower() == job['fullname'].lower()
        ]

    def format_running_jobs(self, jobs):
        if len(jobs) == 0:
            return 'No running jobs.'

        jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs]
        return '\n\n'.join([
            '%s (%s)\n%s' % (job['name'], job['lastBuild']['url'],
                             job['healthReport'][0]['description'])
            for job in jobs_info
        ]).strip()

    @staticmethod
    def format_jobs(jobs):
        if len(jobs) == 0:
            return 'No jobs found.'

        max_length = max([len(job['fullname']) for job in jobs])
        return '\n'.join([
            '%s (%s)' % (job['fullname'].ljust(max_length), job['url'])
            for job in jobs
        ]).strip()

    @staticmethod
    def format_params(job):
        """Format job parameters."""
        if len(job) == 0:
            return 'This job is not parameterized.'
        PARAM_TEMPLATE = Template("""{% for p in params %}Type: {{p.type}}
Description: {{p.description}}
Default Value: {{p.defaultParameterValue.value}}
Parameter Name: {{p.name}}

{% endfor %}""")
        return PARAM_TEMPLATE.render({'params': job})

    @staticmethod
    def format_notification(body):
        body['fullname'] = body.get('fullname', body['name'])
        NOTIFICATION_TEMPLATE = Template("""Build #{{build.number}} \
{{build.status}} for Job {{fullname}} ({{build.full_url}})
{% if build.scm %}Based on {{build.scm.url}}/commit/{{build.scm.commit}} \
({{build.scm.branch}}){% endif %}""")
        return NOTIFICATION_TEMPLATE.render(body)

    @staticmethod
    def build_parameters(params):
        if len(params) > 0:
            return {
                param.split(':')[0]: param.split(':')[1]
                for param in params
            }
        return {'': ''}
Exemplo n.º 21
0
def test_jenkins_jobs():
    master = Jenkins('http://127.0.0.1:8080')
    test_job = master.get_job_info('test_job')

    assert test_job['name'] == 'test_job'
    assert test_job['buildable']
Exemplo n.º 22
0
class JenkinsHelper:
    def __init__(self, url, username, password, key, configuration):
        self.configuration = configuration
        self.configuration_prefix = configuration.jenkins_configuration_prefix()
        self.grouped_components = configuration.jenkins_grouped_components()
        self.pullrequest_job = configuration.pullrequest_job()

        self.jenkins_configurations = Jenkins(url, username, password)
        self.build_components_jobs_matrix()
        self.sort_components()

        self.jenkins_builds = jenkinsapi.jenkins.Jenkins(url, username, password)

# Getters
    def get_jobs(self):
        return self.jobs

    def get_components(self):
        return self.components

    def get_pull_request_builds(self):
        job = self.jenkins_builds.get_job(self.pullrequest_job)

        self.pullrequest_builds = {}
        for build_id in job.get_build_ids():
            build = job[build_id]
            self.pullrequest_builds[build.buildno] = {}
            self.pullrequest_builds[build.buildno]['status'] = build.get_status()
            self.pullrequest_builds[build.buildno]['url'] = build.baseurl
            self.pullrequest_builds[build.buildno]['name'] = build.name

            revision = build.get_revision_branch()[0]
            self.pullrequest_builds[build.buildno]['revision'] = revision['SHA1']
            self.pullrequest_builds[build.buildno]['revision_name'] = revision['name']

        return self.pullrequest_builds

# Helper methods
    def initial_jobs_info(self):
        wanted_jobs, wanted_ids = self.configuration.jenkins_jobs()
        jobs = self.wanted_jobs(wanted_jobs)
        return self.add_human_name_to_job(jobs, wanted_ids)

    def sort_components(self):
        self.components = OrderedDict(sorted(self.components.items(), key=lambda x: self.sorting_modification(x)))

    def build_components_jobs_matrix(self):
        self.jobs = self.initial_jobs_info()

        self.components = {}
        for job in self.jobs:
            groups = {}
            job_raw_components = self.jenkins_configurations.get_job_info(job['name'])["activeConfigurations"]

            job['components'] = {}
            for raw_component in job_raw_components:
                self.process_component(raw_component, job, groups)

            for name, group in groups.iteritems():
                job['components'][name] = group
                self.add_group_to_components(name, group)

    def add_group_to_components(self, name, group):
        self.components[name] = {}
        self.components[name]['name'] = group['name']
        self.components[name]['global_class'] = 'group'
        self.components[name]['type'] = 'group';

    def process_component(self, raw_component, job, groups):
        name = raw_component['name'].replace(self.configuration_prefix, '')

        if name not in self.components:
            self.components[name] = {}
            self.components[name]['name'] = name

        job['components'][name] = {};
        job['components'][name]['name'] = name;
        job['components'][name]['color'] = raw_component['color']
        job['components'][name]['href'] = raw_component['url']

        # Manage grouped components
        grouped_component = self.has_to_be_grouped(name, self.grouped_components)
        if grouped_component:
            self.components[name]['global_class'] = grouped_component + ' hide grouped'

            # Create component group entry
            group_name = grouped_component + '_grouped'
            if not group_name in groups:
                groups[group_name] = {'name': grouped_component, 'color': ''}

            groups[group_name]['color'] = self.logical_color_conjunction(
                                                        groups[group_name]['color'],
                                                        raw_component['color'])

# Second level helper methods
    def wanted_jobs(self, wanted_jobs):
        jobs = self.jenkins_configurations.get_jobs()

        return [ job for job  in jobs if job['name'] in wanted_jobs ]

    def add_human_name_to_job(self, jobs, wanted_jobs_ids):
        for i in range(len(jobs)):
            jobs[i]['short_name'] = wanted_jobs_ids[i]

        return jobs


    def has_to_be_grouped(self, name, grouped_configuration):
        for keyword in grouped_configuration:
            if name.find(keyword) == 0:
                return keyword

        return False


    def logical_color_conjunction(self, color1, color2):
        if (color1 == 'red' or color2 == 'red'):
            return 'red'
        if (color1 == 'yellow' or color2 == 'yellow'):
            return 'yellow'
        if (color1 == 'blue' or color2 == 'blue'):
            return 'blue'

        return 'white'

    def sorting_modification(self, value):
        if ('type' in value[1]) and (value[1]['type'] == 'group'):
            return value[1]['name']

        return value[0] + "_"
Exemplo n.º 23
0
class JC:
    def __init__(self):
        self.JCDirectoryLoc = ''
        self.JCBuiltFileLoc = ''
        self.JCServerConfFileLoc = ''
        self.JenkinsServerAddress = 'none'
        self.JenkinsServerPort = 'none'
        self.ServerHandler = None
        self.IpRegex = '''^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\.( 
            25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\.( 
            25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\.( 
            25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)'''

        self.JCSelectedJobCommands = {
            '(enable)': ' - Enable the specified job on Jenkins Server',
            '(disable)': ' - Disable the specified job on Jenkins Server',
            '(build)': ' - Build the specified job on Jenkins Server',
            '(stat [*])': ' - Displays status and general information about the specified job',
            '(?)': ' - Displays list of available commands',
            '(??)': ' - Displays list of available commands verbosely',
            '(quit/exit)': ' - Quit Job configuration mode'

        }

        self.JigGlobalCommands = {
            '(show local jobs [*])': ' - Displays all jobs saved and waiting in your local machine to be created on server',
            '(show server jobs)': ' - Displays all jobs currently on your jenkins server',
            '(show build queue)': ' - Displays all jobs in build queue',
            '(delete local job)': ' - Deletes jobs on your local machine',
            '(delete server job)': ' - Deletes jobs on your jenkins server',
            '(reconfig server job)': ' - Reconfigures an existing job',
            '(select server job)': ' - Selects job and enter job configuration mode',
            '(connect)': ' - Connects to jenkins server',
            '(disconnect)': ' - Disconnects from jenkins server',
            '(create server job)': ' - Creates a new job on server ',
            '(?)': ' - Displays list of available commands',
            '(??)': ' - Displays list of available commands verbosely',
            '(exit / quit)': ' - Quit JC program'

        }

    def initialize(self):

        fh=open("C:\\Users\{0}\JC\controls".format(getuser()))
        for line in fh:
            if line.startswith('server.conf'):
                self.JCServerConfFileLoc=(line.split("=")[1]).strip()
            elif line.startswith('jobdir'):
                self.JCDirectoryLoc=(line.split("=")[1]).strip()
            elif line.startswith('built'):
                self.JCBuiltFileLoc=(line.split("=")[1]).strip()
            elif line.startswith('address'):
                self.JenkinsServerAddress=(line.split("=")[1]).strip()
            elif line.startswith('port'):
                self.JenkinsServerPort=(line.split("=")[1]).strip()
        fh.close()


    def display_introduction(self):
        '''
        Display an introduction message for the program containing the version and status of
        development
        '''

        print("     Welcome to JC 1.4")
        print("JC is a project which creates an interface to manage your Jenkins Server for your projects")
        print("This project is still under development ")

    def display_list_of_global_mode_commands(self, verbos=False, search_key=None):
        '''
        Display list of available commands in global mode

        :param verbos:  display description of command(s) if true
        :param search_key: display all commands starts with the 'key' param . default is None meaning all available commands

        '''

        print("---------------Commands---------------")
        if search_key is None:
            for command, description in self.JigGlobalCommands.items():
                print(command, description if verbos else '')
        else:
            for command, description in self.JigGlobalCommands.items():

                if command.startswith('({0}'.format(search_key)):
                    print(command, description if verbos else '')
        print("---------------------------------------")

    def display_list_of_selected_job_mode_commands(self, verbos=False, search_key=None):

        '''
        Display list of available commands in selected job mode

        :param verbos: display description of command(s) if true
        :param search_key: display all commands starts with the 'key' param . default is None meaning all available commands

        '''

        print("---------------Commands---------------")
        if search_key is None:
            for command, description in self.JCSelectedJobCommands.items():
                print(command, description if verbos else '')
        else:
            for command, description in self.JCSelectedJobCommands.items():
                if command.startswith('({0}'.format(search_key)):
                    print(command, description if verbos else '')
        print("---------------------------------------")

    def show_local_jobs(self, Detail=False):
        '''
        Display list of local jobs
        :param Detail: If True , Displays more detail about local jobs
        :return:
        '''

        # TODO display format
        if len(listdir(self.JCDirectoryLoc)) == 0:
            print("No local job")
        else:
            if Detail:
                print("Status".ljust(8), "CRL".ljust(23), "CRS".ljust(23), "RCFG".ljust(23), "Name")
                print("-----".ljust(8), "--------".ljust(23), "--------".ljust(23), "--------".ljust(23), "-----")

            else:
                print("Status".ljust(8),"Name".ljust(20))
                print("-----".ljust(8), "-----".ljust(33))

            fhandle = open(self.JCBuiltFileLoc)
            for line in fhandle:
                line = line.strip()
                if line.startswith("#"):
                    pass
                else:
                    if Detail:
                        Status=(line.split("@")[0]).ljust(8)
                        CRL = ((line.split("@")[1]).split(".")[0]).ljust(23)
                        CRS = ((line.split("@")[2]).split(".")[0] if line.split("@")[2]!='None' else 'None').ljust(23)
                        RCFG = ((line.split("@")[3]).split(".")[0] if line.split("@")[3]!='None' else 'None').ljust(23)
                        Name= (line.split("@")[4])
                        print(Status,CRL,CRS,RCFG,Name)
                    else:
                        Status = (line.split("@")[0]).ljust(8)
                        Name= (line.split("@")[4])
                        print(Status,Name)

            fhandle.close()



    def connect_to_jenkins_server(self):

        # Because if there is a problem in reading server.conf file
        # both IP address and Port number becomes none
        # so we just check server address to be none or not


        fh=open("C:\\Users\{0}\JC\controls".format(getuser()))
        for line in fh:
            if line.startswith('address'):
                self.JenkinsServerAddress=(line.split("=")[1]).strip()
            elif line.startswith('port'):
                self.JenkinsServerPort=(line.split("=")[1]).strip()
        fh.close()

        if self.JenkinsServerAddress !='none':
            print("Connecting {0}:{1}".format(self.JenkinsServerAddress, self.JenkinsServerPort))
            UserName = input("Username : "******"Password : "******"Connected successfully as {2}".format(self.JenkinsServerAddress, self.JenkinsServerPort, UserName))
            except:
                self.ServerHandler = None
                print("Connection to server Failed")

        else:
            print("-Server configuration parameters are not defined properly")
            print("-Check server.conf for parameters and then use jcr.exe to set them")


    def is_connected(self):
        '''
        Check whether we are connected to server or not
        '''
        return True if self.ServerHandler else False

    def disconnect_from_jenkins_server(self, place=None):
        '''
        Disconnect from the server
        :param place: Defines the place we are disconnecting . Displayed message can be different based on this parameter
        '''
        # TODO Close the TCP PORT

        if self.ServerHandler == None:
            # Disconnect and Stay in the program
            if place is None:
                print("You are already disconnected")
            return
        self.ServerHandler = None
        # Disconnect while exiting the program
        print("You are disconnected successfully")

    def create_server_job(self, JobName):
        '''
        Create a server job based on a config.xml file existing on the local machine
        :param JobName: job's name to be created
        '''

        if self.ServerHandler is None:
            print("Your are not connected to server")
            print("First connect by 'connect' command")
            return
        if not path.exists('{0}{1}{2}'.format(self.JCDirectoryLoc, JobName, '.config.xml')):
            print("-Job '{0}' config.xml file does not exist on your local machine".format(JobName))
            print("First create a config.xml file for job {0} by jigjr command".format(JobName))
        else:
            ListServerJobs = [server_job["name"] for server_job in self.ServerHandler.get_jobs()]
            if JobName in ListServerJobs:
                print("-Job '{0}' already exists on the server".format(JobName))
                AskingResult = self.asking_user_decision("Do you want to recreate job {0}?[y/n] : ".format(JobName))

                if AskingResult:
                    self.ServerHandler.delete_job(JobName)
                    print("-Deleting job '{0}' from server ..".format(JobName))

                    fhandle = open(self.JCDirectoryLoc + JobName + ".config.xml")
                    SelectedJobXml = fhandle.read()
                    fhandle.close()
                    self.ServerHandler.create_job(JobName, SelectedJobXml)
                    print("-Job '{0}' recreated successfully".format(JobName))

                    # Recreate a job is similar to reconfigure that job
                    update_built_file(self.JCBuiltFileLoc, 'update-reconfigure-date', JobName,
                                      reconfig_date=datetime.now())

            else:
                AskingResult = self.asking_user_decision("Sure creating job {0}?[y/n] : ".format(JobName))
                if AskingResult:
                    fhandle = open(self.JCDirectoryLoc + JobName + ".config.xml")
                    SelectedJobXml = fhandle.read()
                    fhandle.close()
                    self.ServerHandler.create_job(JobName, SelectedJobXml)
                    print("-Job '{0}' created successfully".format(JobName))
                    update_built_file(self.JCBuiltFileLoc, 'update-server-create-date', JobName,
                                      server_creation_date=datetime.now())

    def reconfigure_server_job(self, JobName, LocalConfigJobName=None):
        '''
        Reconfigure a server job
        :param JobName: Server job to be configured
        :param LocalConfigJobName:  If None , JobName.config.xml file is searched in local machine , else, LocalConfigJobName.config.xml is searched
        '''
        if self.ServerHandler is None:
            print("Your are not connected to server")
            print("First connect by 'connect' command")
            return
        ListServerJobs = [server_job["name"] for server_job in self.ServerHandler.get_jobs()]
        if JobName not in ListServerJobs:
            print("-Job '{0}' does not exist on the server".format(JobName))

        else:
            ListLocalJobs = [job.split(".")[0] for job in listdir(self.JCDirectoryLoc)]

            # If the LocalConfigJobName is not specified use the JobName as defualt
            LocalConfigJobName = JobName if LocalConfigJobName is None else LocalConfigJobName

            if LocalConfigJobName not in ListLocalJobs:
                print("-Job {0} config.xml file does not exist in your local machine".format(LocalConfigJobName))

            else:
                print("{0}.config.xml found".format(LocalConfigJobName))
                AskingResult = self.asking_user_decision("Sure reconfiguring job {0}?[y/n] : ".format(JobName))
                if AskingResult:
                    fhandle = open(self.JCDirectoryLoc + LocalConfigJobName + ".config.xml")
                    SelectedJobXml = fhandle.read()
                    fhandle.close()
                    self.ServerHandler.reconfig_job(LocalConfigJobName, SelectedJobXml)
                    print("-Job '{0}' reconfigured successfully".format(LocalConfigJobName))
                    update_built_file(self.JCBuiltFileLoc, 'update-reconfigure-date', LocalConfigJobName,
                                      reconfig_date=datetime.now())

    def show_build_queue(self):
        '''
        Display list of jobs which are currently under building process
        '''
        if self.ServerHandler is None:
            print("Your are not connected to server")
            print("First connect by 'connect' command")
            return
        else:
            BuildQueue = self.ServerHandler.get_queue_info()
            if len(BuildQueue) == 0:
                print("No job in build queue")
                return
            else:
                BuildQueueCounter = 1
                for job in BuildQueue:
                    jobInfo = self.ServerHandler.get_job_info(job['task']['name'])
                    print("{0}: {1}\tBuilding No: {2}".format(BuildQueueCounter, job["task"]["name"],
                                                              jobInfo['nextBuildNumber']))
                    BuildQueueCounter += 1

    def show_server_jobs(self):
        '''
        Display list of jobs currently configured on the server
        '''
        if self.ServerHandler is None:
            print("Your are not connected to server")
            print("First connect by 'connect' command")
            return
        else:
            if len(self.ServerHandler.get_jobs()) == 0:
                print("No job currently on the server")
            else:
                ListServerJobs = [server_job["name"] for server_job in self.ServerHandler.get_jobs()]
                # This list is to reduce the latency of display of all jobs
                # First collect information of all jobs then display
                ReadyList = []
                for job in ListServerJobs:
                    JobInfo = self.ServerHandler.get_job_info(job)
                    JobStatus = 'Disabled' if JobInfo['disabled'] else 'Enabled'
                    JobTotalBuilds = "0" if JobInfo['lastBuild'] is None else JobInfo['lastBuild']['number']
                    JobLastBuild = "None" if JobInfo['lastBuild'] is None else datetime.fromtimestamp(
                        self.ServerHandler.get_build_info(job, JobInfo['lastBuild']['number'])['timestamp'] / 1000)
                    ReadyList.append([JobStatus, JobTotalBuilds, JobLastBuild, job])

                print("Status".ljust(8), "Build".ljust(7), "Timestamp".ljust(22), "Name".ljust(20))
                print("-----".ljust(8), "-----".ljust(7), "------".ljust(22), "----".ljust(20))

                for j in ReadyList:
                    print(j[0].ljust(9), str(j[1]).ljust(6),('None' if str(j[2]) == 'None' else str(j[2]).split(".")[0]).ljust(22), j[3].ljust(20))



    def delete_local_job(self, JobName):
        '''
        Delete local jobs
        '''

        LocalJobs = [job.split(".")[0] for job in listdir(self.JCDirectoryLoc)]

        if JobName not in LocalJobs:
            print("-Job '{0}' does not exist in your local machine".format(JobName))
            return
        else:
            AskingResult = self.asking_user_decision("Sure deleting job '{0}'?[y/n] : ".format(JobName))
            if AskingResult:
                remove(self.JCDirectoryLoc + JobName + ".config.xml")
                print("-Job '{0}' removed successfully from your local machine".format(JobName))

                update_built_file(self.JCBuiltFileLoc, 'delete', JobName)

    def delete_server_job(self, JobName):
        '''
        Delete Specified server job
        '''
        if self.ServerHandler is None:
            print("Your are not connected to server")
            print("First connect by 'connect' command")
            return
        else:
            ListServerJobs = [server_job["name"] for server_job in self.ServerHandler.get_jobs()]
            if JobName not in ListServerJobs:
                print("-Job '{0}' does not exist in Jenkins Server".format(JobName))
                return
            else:
                AskingResult = self.asking_user_decision("Sure deleting job '{0}'?[y/n]: ".format(JobName))
                if AskingResult:
                    self.ServerHandler.delete_job(JobName)
                    print("-Job '{0}' removed successfully from server".format(JobName))
                    update_built_file(self.JCBuiltFileLoc, 'update-deploy-status-ND', JobName)

    def disable_server_job(self, JobName):
        '''
        Disable specified server job
        '''

        JobState = self.ServerHandler.get_job_info(JobName)['disabled']
        if JobState:
            print("-Job '{0}' is already disabled".format(JobName))
            return
        self.ServerHandler.disable_job(JobName)
        print("-Job '{0}' successfully disabled".format(JobName))

    def enable_server_job(self, JobName):
        '''
        Enable specified server job
        '''
        JobState = self.ServerHandler.get_job_info(JobName)['disabled']
        if not JobState:
            print("-Job '{0}' is already enabled".format(JobName))
            return
        self.ServerHandler.enable_job(JobName)
        print("-Job '{0}' successfully enabled".format(JobName))

    def build_server_job(self, JobName):
        '''
        Build specified server job
        '''
        JobState = self.ServerHandler.get_job_info(JobName)['disabled']
        if JobState:
            print("-Job '{0}' is disabled and cannot built".format(JobName))
        else:
            self.ServerHandler.build_job(JobName)
            print("-Job '{0}' successfully built".format(JobName))

    def stat_server_job(self, JobName, Detail=False):
        '''
        Display status of the selected job
        :param Detail: If * specified , more detail about job is displayed
        '''

        # Because building a job can take long time we do not display the status
        # until the building process gets done
        BuildQueue = self.ServerHandler.get_queue_info()

        for job in BuildQueue:
            if JobName == job["task"]["name"]:
                print("-Job '{0}' is under building process".format(JobName))
                return

        JobInfo = self.ServerHandler.get_job_info(JobName)
        JobName_Sta = "Name: {0}".format(JobName)
        JobStatus_Sta = "Status: {0}".format('Disabled' if JobInfo['disabled'] else 'Enabled')
        JobTotalBuilds_Sta = "TotalBuilds: {0}".format(
            "0" if JobInfo['lastBuild'] is None else JobInfo['lastBuild']['number'])
        JobLastBuild_Sta = "LastBuild: {0}".format("None" if JobInfo['lastBuild'] is None else datetime.fromtimestamp(
            self.ServerHandler.get_build_info(JobName, JobInfo['lastBuild']['number'])['timestamp'] / 1000))
        JobFirstBuild_Sta = "FirstBuild: {0}".format("None" if JobInfo['lastBuild'] is None else datetime.fromtimestamp(
            self.ServerHandler.get_build_info(JobName, JobInfo['lastBuild']['number'])['timestamp'] / 1000))

        JobLastCompletedBuild_Sta = "LastCompletedBuild: {0}".format(
            "None" if JobInfo['lastCompletedBuild'] is None else str(datetime.fromtimestamp(
                self.ServerHandler.get_build_info(JobName, JobInfo['lastCompletedBuild']['number'])[
                    'timestamp'] / 1000)).split(".")[0])
        JobLastFailedBuild_Sta = "LastFailedBuild: {0}".format(
            "None" if JobInfo['lastFailedBuild'] is None else str(datetime.fromtimestamp(
                self.ServerHandler.get_build_info(JobName, JobInfo['lastFailedBuild']['number'])['timestamp'] / 1000)).split(".")[0])
        JobLastStableBuild_Sta = "LastStableBuild: {0}".format(
            "None" if JobInfo['lastStableBuild'] is None else str(datetime.fromtimestamp(
                self.ServerHandler.get_build_info(JobName, JobInfo['lastStableBuild']['number'])['timestamp'] / 1000)).split(".")[0])
        JobLastSuccessfulBuild_Sta = "LastSuccessfulBuild: {0}".format(
            "None" if JobInfo['lastSuccessfulBuild'] is None else str(datetime.fromtimestamp(
                self.ServerHandler.get_build_info(JobName, JobInfo['lastSuccessfulBuild']['number'])[
                    'timestamp'] / 1000)).split(".")[0])
        JobLastUnstableBuild_Sta = "LastUnstableBuild: {0}".format(
            "None" if JobInfo['lastUnstableBuild'] is None else str(datetime.fromtimestamp(
                self.ServerHandler.get_build_info(JobName, JobInfo['lastUnstableBuild']['number'])['timestamp'] / 1000)).split(".")[0])
        JobLastUnsuccessfulBuild_Sta = "LastUnsuccessfulBuild: {0}".format(
            "None" if JobInfo['lastUnsuccessfulBuild'] is None else str(datetime.fromtimestamp(
                self.ServerHandler.get_build_info(JobName, JobInfo['lastUnsuccessfulBuild']['number'])[
                    'timestamp'] / 1000)).split(".")[0])

        print(JobName_Sta)
        print(JobStatus_Sta)
        print(JobTotalBuilds_Sta)
        print(JobLastBuild_Sta)
        print(JobLastStableBuild_Sta)
        print(JobLastCompletedBuild_Sta)

        if Detail:
            print(JobFirstBuild_Sta)
            print(JobLastFailedBuild_Sta)
            print(JobLastSuccessfulBuild_Sta)
            print(JobLastUnstableBuild_Sta)
            print(JobLastUnsuccessfulBuild_Sta)

    def select_server_job(self, JobName):
        '''
        Select a server job and enter selected job mode
        '''
        if self.ServerHandler is None:
            print("Your are not connected to server")
            print("First connect by 'connect' command")
            return
        else:

            ListServerJobs = [server_job["name"] for server_job in self.ServerHandler.get_jobs()]
            if JobName not in ListServerJobs:
                print("-Job '{0}'  not exist in Jenkins Server".format(JobName))
                return
            else:
                SelectedJobSession = PromptSession(
                    lexer=PygmentsLexer(SqlLexer), completer=selected_job_command_completer)
                while True:

                    try:
                        UserCommand = SelectedJobSession.prompt("(" + JobName + ')## ')
                        UserCommand = (sub(' +', ' ', UserCommand)).strip()

                        if UserCommand.startswith("??"):
                            keyValue = (UserCommand.split("??")[1].strip())
                            if keyValue == '':
                                jc.display_list_of_selected_job_mode_commands(verbos=True)
                            else:
                                jc.display_list_of_selected_job_mode_commands(search_key=keyValue, verbos=True)

                        elif UserCommand.startswith("?"):
                            keyValue = (UserCommand.split("?")[1].strip())

                            if keyValue == '':
                                jc.display_list_of_selected_job_mode_commands()
                            else:
                                jc.display_list_of_selected_job_mode_commands(search_key=keyValue)


                        elif UserCommand == "quit" or UserCommand == "exit":
                            return

                        elif UserCommand == "enable":
                            self.enable_server_job(JobName)

                        elif UserCommand == "disable":
                            self.disable_server_job(JobName)

                        elif UserCommand == "build":
                            self.build_server_job(JobName)

                        elif UserCommand == 'stat *':
                            self.stat_server_job(JobName, Detail=True)

                        elif UserCommand == 'stat':
                            self.stat_server_job(JobName)

                        elif UserCommand == "":
                            pass
                        else:
                            print("%Invalid Command")

                    except KeyboardInterrupt:
                        break
                    except EOFError:
                        break
                    except:
                        print("There was a problem in program")
                        return

    def get_whoami(self):
        '''
        Display who is connected to server
        '''
        if self.ServerHandler is None:
            print("Your are not connected to server")
            print("First connect by 'connect' command")
            return
        else:
            UserInfo = self.ServerHandler.get_whoami()
            print("Full Name : ", UserInfo["fullName"])
            print("Id : ", UserInfo["id"])

    def asking_user_decision(self, displayMessage):
        '''
        This process is repeated many times in the code asking the user for yes/no answer
        so this process is turned into a function for simplicity

        :param displayMessage:  Message to be displayed for asking user his/her decision
        '''

        while True:
            UserDecision = input(displayMessage)
            if UserDecision.lower() in "y yes ye":
                return True
            elif UserDecision.lower() in "n no":
                return False

    def get_job_directory(self):
        return self.JCDirectoryLoc
class JenkinsNotifier(BotPlugin):
    """JenkinsBot is an Err plugin to manage Jenkins CI jobs from your chat platform like Slack."""

    status = {'blue':'SUCCESS', 'blue_anime':'IN PROGRESS','red': 'FAILED', 'red_anime': 'IN PROGRESS', 'disabled':   'DISABLED', 'aborted':'ABORTED', 'notbuilt': 'NOTBUILT', 'yellow': 'UNSTABLE'}
    failedjobsstring = " "


    def __init__(self, bot, name):
        self.jenkins = Jenkins(JENKINS_URL, JENKINS_USERNAME, JENKINS_TOKEN)
        super().__init__(bot, name) 


    @botcmd(split_args_with=None)
    def jn_build(self, msg, args):
        """Build the job specified by jobName. You can add params!"""

        # Params are passed like "key1=value1 key2=value2"
        params = {}
        #try:
        #    for arg in args[1:]:
        #        params[arg.split('=', 1)[0]] = arg.split('=', 1)[1]
        #except IndexError:
        #    return "I don'G like that params! Try with this format: key1=value1 key2=value2..."
        jobName = ''.join([args[0],' ',args[1]]) #TODO handle jobname with spaces in it, space is cosidered argument splitter  
        try:
            self.jenkins.build_job(jobName, params)
        except NotFoundException:
            return ' '.join(["Sorry, I can't find the job. Typo maybe?"," ARGS=",jobName])

        return ' '.join(["The job", args[0].strip(), "has been sent to the queue to be built."])


    @botcmd
    def jn_cancel(self, msg, args):
        """Cancel a job in the queue by jobId."""

        try:
            self.jenkins.cancel_queue(args.strip())
        except NotFoundException:
            return "Sorry, I can't find the job. Maybe the ID does not exist."

        return "Job canceled from the queue."


    @botcmd
    def jn_list(self, msg, args):
        """List Jenkins jobs. You can filter with strings."""

        self.send(msg.to, "I'm getting the jobs list from Jenkins...")

        search_term = args.strip().lower()
        jobs = [job for job in self.jenkins.get_jobs()
                if search_term.lower() in job['name'].lower()]

        return self.format_jobs(jobs)


    @botcmd
    def jn_status(self, msg, args):
        """List Jenkins jobs with their current status."""

        self.send(msg.to, "I'm getting the jobs with status Jenkins...")

        search_term = args.strip().lower()
        jobs = [job for job in self.jenkins.get_jobs()
                if search_term.lower() in job['fullname'].lower()]

        return self.format_job_status(jobs)




    @botcmd
    def jn_describe(self, msg, args):
        """Describe the job specified by jobName."""

        try:
            job = self.jenkins.get_job_info(args.strip())
        except NotFoundException:
            return "Sorry, I can't find the job. Typo maybe?"

        return ''.join([
            'Name: ', job['name'], '\n',
            'URL: ', job['url'], '\n',
            'Description: ', 'None' if job['description'] is None else job['description'], '\n',
            'Next Build Number: ',
            str('None' if job['nextBuildNumber'] is None else job['nextBuildNumber']), '\n',
            'Last Successful Build Number: ',
            str('None' if job['lastBuild'] is None else job['lastBuild']['number']), '\n',
            'Last Successful Build URL: ',
            'None' if job['lastBuild'] is None else job['lastBuild']['url'], '\n'
        ])


    @botcmd
    def jn_running(self, msg, args):
        """List running jobs."""

        self.send(msg.to, "I will ask for the current running builds list!")

        jobs = self.jenkins.get_running_builds()

        return self.format_running_jobs(jobs)


    @botcmd(split_args_with=None)
    def jn_stop(self, msg, args):
        """Stop the building job specified by jobName and jobNumber."""

        try:
            int(args[1].strip())
        except ValueError:
            return "You have to specify the jobNumber: \"!jenkins stop <jobName> <jobNumber>"

        try:
            self.jenkins.stop_build(args[0].strip(), int(args[1].strip()))
        except NotFoundException:
            return "Sorry, I can't find the job. Typo maybe?"

        return ' '.join(["The job", args[0].strip(), "has been stopped."])


    @botcmd
    def jn_queue(self, msg, args):
        """List jobs in queue."""

        self.send(msg.to, "Getting the job queue...")

        jobs = self.jenkins.get_queue_info()

        return self.format_queue_jobs(jobs)


    @botcmd
    def jn_msgtimer(self, msg, args):
        """Sends messages at fix intervals."""
        yield "Starting timer"
        self.start_poller(5, self.my_callback)
        self.send(msg.to,
        "Boo! Bet you weren't expecting me, were you?", 
        )


    def my_callback(self):
        self.log.info('I am called every 5sec')
        self.send(self.build_identifier("#errbottestchannel"), "I am called every 5sec", )

    @botcmd 
    def jn_failed(self, msg, args):

        """List Jenkins jobs with failed status."""
        self.send(msg.to, "I'm getting the failed jobs ...")
        failedJobs = []
        search_term = args.strip().lower()
        jobs = [job for job in self.jenkins.get_jobs()
                if search_term.lower() in job['fullname'].lower()]
        for job in jobs:
            if self.status[job['color']] == 'FAILED':
               failedJobs.append(job)
        return self.format_job_status(failedJobs)



# SUPPORT FUNCTIONS START HERE

    def format_jobs(self, jobs):
        """Format jobs list"""

        if len(jobs) == 0:
            return "I haven't found any job."

        max_length = max([len(job['name']) for job in jobs])
        return '\n'.join(['%s (%s)' % (job['name'].ljust(max_length),
                                       job['url']) for job in jobs]).strip()


    def format_queue_jobs(self, jobs):
        """Format queue jobs list"""

        if len(jobs) == 0:
            return "It seems that there is not jobs in queue."

        return '\n'.join(['%s - %s (%s)' % (str(job['id']),
                                            job['task']['name'],
                                            job['task']['url']) for job in jobs]).strip()


    def format_running_jobs(self, jobs):
        """Format running jobs list"""

        if len(jobs) == 0:
            return "There is no running jobs!"

        return '\n'.join(['%s - %s (%s) - %s' % (str(job['number']),
                                                 job['name'],
                                                 job['url'],
                                                 job['executor']) for job in jobs]).strip()

    @botcmd
    def jn_queue(self, msg, args):
        """List jobs in queue."""

        self.send(msg.to, "Getting the job queue...")

        jobs = self.jenkins.get_queue_info()

        return self.format_queue_jobs(jobs)


    def format_jobs(self, jobs):
        """Format jobs list"""

        if len(jobs) == 0:
            return "I haven't found any job."

        max_length = max([len(job['name']) for job in jobs])
        return '\n'.join(['%s (%s)' % (job['name'].ljust(max_length),
                                       job['url']) for job in jobs]).strip()


    def format_queue_jobs(self, jobs):
        """Format queue jobs list"""

        if len(jobs) == 0:
            return "It seems that there is not jobs in queue."

        return '\n'.join(['%s - %s (%s)' % (str(job['id']),
                                            job['task']['name'],
                                            job['task']['url']) for job in jobs]).strip()


    def format_running_jobs(self, jobs):
        """Format running jobs list"""

        if len(jobs) == 0:
            return "There is no running jobs!"

        return '\n'.join(['%s - %s (%s) - %s' % (str(job['number']),
                                                 job['name'],
                                                 job['url'],
                                                 job['executor']) for job in jobs]).strip()

    def format_job_status(self, jobs):
        """Format job status"""

        if len(jobs) == 0:
            return "there are no jobs to return"
        return '\n'.join(['%s (%s)' % (job['fullname'], self.status[job['color']]) for job in jobs]).strip()
Exemplo n.º 25
0
class jenkinscls(object):
    def __init__(self):
        self.url = config.JENKINS_URL
        self.username = config.JENKINS_NAME
        self.token = config.JENKINS_TOKEN
        self.j = Jenkins(config.JENKINS_URL,
                         username=config.JENKINS_NAME,
                         password=config.JENKINS_TOKEN)

    def getjobnames(self, strval=''):
        rs = {r'...': r'/'}
        s = utils.multiple_replace(str(strval), rs).split('/')
        return s[0], "/".join(s[1:])

    def getlenstr(self, strval, n):
        return str(strval)[0:n]

    def getstatus(self, strval):
        if str(strval) == 'FAILURE':
            return 'error'
        elif str(strval) == 'ABORTED':
            return 'aborted'
        elif str(strval) == 'SUCCESS':
            return 'success'
        else:
            return 'started'

    def edit_userjob_config(self, jn, obj):
        n, r = self.getjobnames(jn)
        try:
            desobj = callback()
            desobj.des = obj['description']
            desobj.callback_url = ""
            desobj.build_id = ''
            desobj.duration = ''
            desobj.namespace = n
            desobj.image_name = obj['image_name']
            desobj.repo_name = r
            desobj.status = ''
            desobj.tag = obj['build_config']['tag_configs']['docker_repo_tag']
            desobj.time = ''

            ss = xmltodict.parse(self.getbasejob_config())
            jsonpickle.set_preferred_backend('json')
            ss['project']['description'] = jsonpickle.encode(desobj)
            ss['project']['properties']['com.tikal.hudson.plugins.notification.HudsonNotificationProperty']['endpoints'] \
                ['com.tikal.hudson.plugins.notification.Endpoint']['url'] = config.JOBHOOKURL

            ss['project']['scm']['userRemoteConfigs']['hudson.plugins.git.UserRemoteConfig'] \
                ['url'] = obj['build_config']['code_repo_clone_url']
            ss['project']['scm']['branches']['hudson.plugins.git.BranchSpec'] \
                ['name'] = '*/' + obj['build_config']['tag_configs']['code_repo_type_value']
            ss['project']['builders']['hudson.tasks.Shell'][
                'command'] = config.JOBCOMMON1
            ss['project']['builders']['com.cloudbees.dockerpublish.DockerBuilder']['registry'] \
                ['url'] = config.REGISTRYURL
            b = str(obj['build_config']['tag_configs']['build_cache_enabled'])
            ss['project']['builders']['com.cloudbees.dockerpublish.DockerBuilder']['noCache'] \
                = ('true' if b == 'false' else 'false')
            ss['project']['builders']['com.cloudbees.dockerpublish.DockerBuilder']['dockerfilePath'] \
                = obj['build_config']['tag_configs']['dockerfile_location']
            ss['project']['builders']['com.cloudbees.dockerpublish.DockerBuilder']['repoTag'] \
                = obj['build_config']['tag_configs']['docker_repo_tag']
            ss['project']['builders']['com.cloudbees.dockerpublish.DockerBuilder']['repoName'] \
                = obj['image_name']

            return xmltodict.unparse(ss)
        except Exception as e:
            print e.message

    def edit_docker_load_job_config(self, obj):

        try:
            # {docker_login} && docker import {httpfilename} {imagename} && docker push {imagename}
            ss = xmltodict.parse(self.getdocker_load_config())
            desobj = callback()
            desobj.des = obj['export_file_url']
            desobj.callback_url = obj['post_callback_url']
            desobj.build_id = obj['build_id']
            desobj.duration = ''
            desobj.namespace = ""
            desobj.repo_name = ""
            desobj.image_name = obj['image_name']
            desobj.status = ''
            desobj.tag = obj['tag']
            desobj.time = ''
            jsonpickle.set_preferred_backend('json')
            ss['project']['description'] = jsonpickle.encode(desobj)
            ss['project']['properties']['com.tikal.hudson.plugins.notification.HudsonNotificationProperty']['endpoints'] \
                ['com.tikal.hudson.plugins.notification.Endpoint']['url'] = config.JOBHOOKURL
            tempstr = str(
                ss['project']['builders']['hudson.tasks.Shell']['command'])
            s = {
                r'{docker_login}':
                config.JOBCOMMON1,
                r'{httpfilename}':
                obj['export_file_url'],
                r'{imagename}':
                config.REGISTRYNAME + '/' + obj['image_name'] + ':' +
                obj['tag']
            }
            ss['project']['builders']['hudson.tasks.Shell'][
                'command'] = utils.multiple_replace(tempstr, s)

            return xmltodict.unparse(ss)
        except Exception as e:
            print e.message

    def edit_docker_sync_job_config(self, obj):

        try:
            # {docker_login} && docker pull {oldimage} && docker tag {oldimage} {newimage} && docker push {newimage}
            ss = xmltodict.parse(self.getdocker_sync_config())
            jsonUtil = JsonUtil()
            c = jsonUtil.parseJsonString(config.CLOUD_CONFIG)
            cid = obj['sync_cloud_id']
            desobj = callback()
            desobj.des = ""
            desobj.callback_url = obj['post_callback_url']
            desobj.build_id = ''
            desobj.duration = ''
            desobj.namespace = ""
            desobj.repo_name = obj['sync_cloud_id']  # 把cloudid 临时存在 这
            desobj.image_name = obj['image_name']
            desobj.status = ''
            desobj.tag = obj['tag']
            desobj.time = ''
            jsonpickle.set_preferred_backend('json')
            ss['project']['description'] = jsonpickle.encode(desobj)
            ss['project']['properties']['com.tikal.hudson.plugins.notification.HudsonNotificationProperty']['endpoints'] \
                ['com.tikal.hudson.plugins.notification.Endpoint']['url'] = config.JOBHOOKURL+'?cloudid='+obj['sync_cloud_id']
            tempstr = str(
                ss['project']['builders']['hudson.tasks.Shell']['command'])
            s = {
                r'{docker_login}':
                c[cid]['login_common'],
                r'{oldimage}':
                config.REGISTRYNAME + '/' + obj['image_name'] + ':' +
                obj['tag'],
                r'{newimage}':
                c[cid]['registry_name'] + '/' + obj['image_name'] + ':' +
                obj['tag']
            }
            ss['project']['builders']['hudson.tasks.Shell'][
                'command'] = utils.multiple_replace(tempstr, s)

            return xmltodict.unparse(ss)
        except Exception as e:
            print e.message

    def updateconfig_buildid(self, jn, imagename, build_id, callback_url):
        try:
            ss = xmltodict.parse(self.j.get_job_config(jn))
            jsonpickle.set_preferred_backend('json')
            desobj = jsonpickle.decode(ss['project']['description'])
            if str(desobj.build_id) == str(build_id):
                return True
            desobj.build_id = build_id
            desobj.callback_url = callback_url
            desobj.image_name = imagename
            ss['project']['description'] = jsonpickle.encode(desobj)

            self.j.reconfig_job(jn, xmltodict.unparse(ss))

            return True
        except Exception as e:
            print e.message
            return False

    @gen.coroutine
    def posthook(self, obj):
        # s = {r'/': r'...'}
        jn = obj['name']
        bid = str(obj['build']['number'])
        # n, r = self.getjobnames(jn)
        re = hook()
        try:
            info = self.j.get_build_info(jn, int(bid))
            if self.j.job_exists(jn):
                ss = xmltodict.parse(self.j.get_job_config(jn))
                jsonpickle.set_preferred_backend('json')

                if isinstance(jsonpickle.decode(ss['project']['description']),
                              callback):
                    desobj = jsonpickle.decode(ss['project']['description'])
                    re.namespace = desobj.namespace
                    re.repo_name = desobj.repo_name
                    re.build_id = str(obj['build']['number'])
                    re.status = self.getstatus(obj['build']['status'])
                    re.duration = info['duration']
                    re.tag = desobj.tag
                    re.time = datetime.now()
                    re.callurl = desobj.callback_url
        except Exception as e:
            print e.message
            re = None
        raise gen.Return(re)

    @gen.coroutine
    def post_docker_load_hook(self, obj):

        jn = obj['name']
        bid = str(obj['build']['number'])

        re = postimage()
        try:
            # info = self.j.get_build_info(jn, int(bid))
            if self.j.job_exists(jn):
                ss = xmltodict.parse(self.j.get_job_config(jn))
                jsonpickle.set_preferred_backend('json')

                if isinstance(jsonpickle.decode(ss['project']['description']),
                              callback):
                    desobj = jsonpickle.decode(ss['project']['description'])
                    re.image_name = desobj.image_name
                    re.status = self.getstatus(obj['build']['status'])
                    re.tag = desobj.tag
                    re.export_file_url = desobj.des
                    re.time = datetime.now()
                    re.build_id = desobj.build_id
                    re.post_callback_url = desobj.callback_url
                    if re.status != 'error' and config.JENKINS_IMAGEOPTJOB_DELETE == 'true':
                        self.j.delete_job(jn)

        except Exception as e:
            print e.message
            re = None
        raise gen.Return(re)

    @gen.coroutine
    def post_docker_sync_hook(self, obj, cloudid):
        jn = obj['name']
        # bid = str(obj['build']['number'])
        jsonUtil = JsonUtil()
        c = jsonUtil.parseJsonString(config.CLOUD_CONFIG)
        j = Jenkins(c[cloudid]['jenkins_url'],
                    username=c[cloudid]['jenkins_name'],
                    password=c[cloudid]['jenkins_token'])

        re = postimagesync()
        try:

            if j.job_exists(jn):
                ss = xmltodict.parse(j.get_job_config(jn))
                jsonpickle.set_preferred_backend('json')

                if isinstance(jsonpickle.decode(ss['project']['description']),
                              callback):
                    desobj = jsonpickle.decode(ss['project']['description'])
                    re.image_name = desobj.image_name
                    re.status = self.getstatus(obj['build']['status'])
                    re.sync_cloud_id = desobj.repo_name
                    re.tag = desobj.tag
                    re.time = datetime.now()
                    re.post_callback_url = desobj.callback_url
                    if re.status != 'error' and config.JENKINS_IMAGEOPTJOB_DELETE == 'true':
                        j.delete_job(jn)

        except Exception as e:
            print e.message
            re = None
        raise gen.Return(re)

    @gen.coroutine
    def createjob(self, jobname, obj):
        s = {r'/': r'...'}
        jn = utils.multiple_replace(jobname, s)
        n, r = self.getjobnames(jn)
        try:
            if self.j.job_exists(jn):
                re = createrespo(n, r, '工程已存在', 'error', datetime.now())
            self.j.create_job(jn, self.edit_userjob_config(jn, obj))
            re = createrespo(n, r, '', 'success', datetime.now())
        except Exception as e:
            print e.message
            re = createrespo(n, r, '', 'error', datetime.now())
        raise gen.Return(re)

    @gen.coroutine
    def create_docker_load_job(self, obj):
        # s = {r'/': r'...'}
        # jn = utils.multiple_replace(jobname, s)
        s = utils.randomstr(8)
        jn = '__docker_load_job_' + s
        re = postimage()
        re.created_at = datetime.now()
        re.image_name = obj['image_name']
        re.build_id = str(obj['build_id'])
        re.post_callback_url = obj['post_callback_url']
        re.tag = obj['tag']
        re.status = 'started'
        try:
            if self.j.job_exists(jn):
                jn = jn + utils.randomstr(4)
                x = self.edit_docker_load_job_config(obj)
                self.j.create_job(jn, x)
                yield gen.sleep(0.5)
                self.j.build_job(jn)
            x = self.edit_docker_load_job_config(obj)
            self.j.create_job(jn, x)
            yield gen.sleep(0.5)
            self.j.build_job(jn)

        except Exception as e:
            print e.message
            re.status = 'error'
        raise gen.Return(re)

    @gen.coroutine
    def create_docker_sync_job(self, obj):
        # s = {r'/': r'...'}
        # jn = utils.multiple_replace(jobname, s)
        s = utils.randomstr(8)
        jn = '__docker_sync_job_' + s
        cid = obj['sync_cloud_id']
        jsonUtil = JsonUtil()
        c = jsonUtil.parseJsonString(config.CLOUD_CONFIG)
        j = Jenkins(c[cid]['jenkins_url'],
                    username=c[cid]['jenkins_name'],
                    password=c[cid]['jenkins_token'])
        re = postimagesync()
        re.time = datetime.now()
        re.sync_cloud_id = obj['sync_cloud_id']
        re.image_name = obj['image_name']
        re.post_callback_url = obj['post_callback_url']
        re.tag = obj['tag']
        re.status = 'started'
        try:
            if j.job_exists(jn):
                jn = jn + utils.randomstr(4)
                j.create_job(jn, self.edit_docker_sync_job_config(obj))
                yield gen.sleep(0.5)
                j.build_job(jn)
            j.create_job(jn, self.edit_docker_sync_job_config(obj))
            yield gen.sleep(0.5)
            j.build_job(jn)
        except Exception as e:
            print e.message
            re.status = 'error'
        raise gen.Return(re)

    @gen.coroutine
    def editjob(self, jobname, obj):
        s = {r'/': r'...'}
        jn = utils.multiple_replace(jobname, s)
        n, r = self.getjobnames(jn)
        try:
            if self.j.job_exists(jn):
                self.j.reconfig_job(jn, self.edit_userjob_config(jn, obj))
                re = createrespo(n, r, '', 'success', datetime.now())
            else:
                re = createrespo(n, r, 'repo is not find', 'error',
                                 datetime.now())
        except Exception as e:
            print e.message
            re = createrespo(n, r, '', 'error', datetime.now())
        raise gen.Return(re)

    @gen.coroutine
    def getjobinfo(self, jobname):
        s = {r'/': r'...'}
        jn = utils.multiple_replace(jobname, s)
        n, r = self.getjobnames(jn)
        re = jobinfo()
        try:
            if self.j.job_exists(jn):
                re.namespace = n
                re.repo_name = r
                re.info = self.j.get_job_info(jn)
        except Exception as e:
            print e.message
            re.namespace = n
            re.repo_name = r
            re.info = ""
        raise gen.Return(re)

    @gen.coroutine
    def deljob(self, jobname):
        s = {r'/': r'...'}
        jn = utils.multiple_replace(jobname, s)
        n, r = self.getjobnames(jn)
        try:
            if self.j.job_exists(jn):
                self.j.delete_job(jn)
            re = delrespo(n, r, 'success')

        except Exception as e:
            print e.message
            re = delrespo(n, r, 'error')
        raise gen.Return(re)

    @gen.coroutine
    def stopbuild(self, jobname, build_id):
        s = {r'/': r'...'}
        jn = utils.multiple_replace(jobname, s)
        n, r = self.getjobnames(jn)
        try:
            if self.j.job_exists(jn) and self.j.get_build_info(
                    jn, int(build_id)):
                self.j.stop_build(jn, int(build_id))
                re = delbuild(n, r, build_id, 'aborted')
            else:
                re = delbuild(n, r, build_id, 'error')

        except Exception as e:
            print e.message
            re = delbuild(n, r, build_id, 'error')
        raise gen.Return(re)

    @gen.coroutine
    def postbuild(self, jobname, imagename, tag, callback_url):
        s = {r'/': r'...'}
        jn = utils.multiple_replace(jobname, s)
        n, r = self.getjobnames(jn)
        try:

            if self.j.job_exists(jn):

                j = self.j.get_job_info(jn)

                build_id = j['nextBuildNumber']

                if self.j.get_queue_info() != []:
                    re = postbuild(n, r, imagename, build_id, tag,
                                   datetime.now(), 'queue')
                elif j['queueItem'] != None:
                    re = postbuild(n, r, imagename, build_id, tag,
                                   datetime.now(), 'queue')
                else:
                    self.updateconfig_buildid(jn, imagename, build_id,
                                              callback_url)
                    self.j.build_job(jn)
                    re = postbuild(n, r, imagename, build_id, tag,
                                   datetime.now(), 'started')
            else:
                re = postbuild(n, r, '', '', datetime.now(), 'error')

        except Exception as e:
            print e.message
            re = postbuild(n, r, '', tag, datetime.now(), 'error')
        raise gen.Return(re)

    @gen.coroutine
    def getbuild(self, jobname, build_id):
        s = {r'/': r'...'}
        jn = utils.multiple_replace(jobname, s)
        n, r = self.getjobnames(jn)
        try:
            b = self.j.get_build_info(jn, int(build_id))
            building = b['building']
            duration = b['duration']
            dt = self.getlenstr(b['timestamp'], 10)
            started_at = utils.timestamp_datetime(int(dt))
            status = self.getstatus(b['result'])
            stdout = self.j.get_build_console_output(jn, int(build_id))
            bd = build_detail(n, r, build_id, building, started_at, duration,
                              status, stdout)
        except Exception as e:
            print e.message
            bd = build_detail(n, r, build_id, '', '', '', 'error', '')
        raise gen.Return(bd)

    def getdocker_sync_config(self):
        s = '''<?xml version='1.0' encoding='UTF-8'?>
<project>
  <actions/>
  <description></description>
  <keepDependencies>false</keepDependencies>
  <properties>
    <com.tikal.hudson.plugins.notification.HudsonNotificationProperty plugin="[email protected]">
      <endpoints>
        <com.tikal.hudson.plugins.notification.Endpoint>
          <protocol>HTTP</protocol>
          <format>JSON</format>
          <url>http://10.1.39.60:8080/v1/hook</url>
          <event>completed</event>
          <timeout>30000</timeout>
          <loglines>0</loglines>
        </com.tikal.hudson.plugins.notification.Endpoint>
      </endpoints>
    </com.tikal.hudson.plugins.notification.HudsonNotificationProperty>
    <com.synopsys.arc.jenkins.plugins.ownership.jobs.JobOwnerJobProperty plugin="[email protected]"/>
    <hudson.plugins.heavy__job.HeavyJobProperty plugin="[email protected]">
      <weight>1</weight>
    </hudson.plugins.heavy__job.HeavyJobProperty>
    <jenkins.model.BuildDiscarderProperty>
      <strategy class="hudson.tasks.LogRotator">
        <daysToKeep>30</daysToKeep>
        <numToKeep>50</numToKeep>
        <artifactDaysToKeep>-1</artifactDaysToKeep>
        <artifactNumToKeep>-1</artifactNumToKeep>
      </strategy>
    </jenkins.model.BuildDiscarderProperty>
    <job-metadata plugin="[email protected]">
      <values class="linked-list">
        <metadata-tree>
          <name>job-info</name>
          <parent class="job-metadata" reference="../../.."/>
          <generated>true</generated>
          <exposedToEnvironment>false</exposedToEnvironment>
          <children class="linked-list">
            <metadata-tree>
              <name>last-saved</name>
              <description></description>
              <parent class="metadata-tree" reference="../../.."/>
              <generated>true</generated>
              <exposedToEnvironment>false</exposedToEnvironment>
              <children class="linked-list">
                <metadata-date>
                  <name>time</name>
                  <description></description>
                  <parent class="metadata-tree" reference="../../.."/>
                  <generated>true</generated>
                  <exposedToEnvironment>false</exposedToEnvironment>
                  <value>
                    <time>1458098001639</time>
                    <timezone>Asia/Shanghai</timezone>
                  </value>
                  <checked>false</checked>
                </metadata-date>
                <metadata-tree>
                  <name>user</name>
                  <parent class="metadata-tree" reference="../../.."/>
                  <generated>true</generated>
                  <exposedToEnvironment>false</exposedToEnvironment>
                  <children class="linked-list">
                    <metadata-string>
                      <name>display-name</name>
                      <description></description>
                      <parent class="metadata-tree" reference="../../.."/>
                      <generated>true</generated>
                      <exposedToEnvironment>false</exposedToEnvironment>
                      <value>admin</value>
                    </metadata-string>
                    <metadata-string>
                      <name>full-name</name>
                      <description></description>
                      <parent class="metadata-tree" reference="../../.."/>
                      <generated>true</generated>
                      <exposedToEnvironment>false</exposedToEnvironment>
                      <value>admin</value>
                    </metadata-string>
                  </children>
                </metadata-tree>
              </children>
            </metadata-tree>
          </children>
        </metadata-tree>
      </values>
    </job-metadata>
  </properties>
  <scm class="hudson.scm.NullSCM"/>
  <scmCheckoutRetryCount>3</scmCheckoutRetryCount>
  <canRoam>true</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
    <hudson.tasks.Shell>
      <command>{docker_login} &amp;&amp; docker pull {oldimage} &amp;&amp; docker tag --force=true {oldimage} {newimage} &amp;&amp; docker push {newimage}
</command>
    </hudson.tasks.Shell>
  </builders>
  <publishers/>
  <buildWrappers>
    <hudson.plugins.ansicolor.AnsiColorBuildWrapper plugin="[email protected]">
      <colorMapName>xterm</colorMapName>
    </hudson.plugins.ansicolor.AnsiColorBuildWrapper>
  </buildWrappers>
</project>'''
        return s

    def getdocker_load_config(self):
        s = '''<?xml version='1.0' encoding='UTF-8'?>
<project>
  <actions/>
  <description></description>
  <keepDependencies>false</keepDependencies>
  <properties>
    <com.tikal.hudson.plugins.notification.HudsonNotificationProperty plugin="[email protected]">
      <endpoints>
        <com.tikal.hudson.plugins.notification.Endpoint>
          <protocol>HTTP</protocol>
          <format>JSON</format>
          <url>http://10.1.39.60:8080/v1/hook</url>
          <event>completed</event>
          <timeout>30000</timeout>
          <loglines>0</loglines>
        </com.tikal.hudson.plugins.notification.Endpoint>
      </endpoints>
    </com.tikal.hudson.plugins.notification.HudsonNotificationProperty>
    <com.synopsys.arc.jenkins.plugins.ownership.jobs.JobOwnerJobProperty plugin="[email protected]"/>
    <hudson.plugins.heavy__job.HeavyJobProperty plugin="[email protected]">
      <weight>1</weight>
    </hudson.plugins.heavy__job.HeavyJobProperty>
    <jenkins.model.BuildDiscarderProperty>
      <strategy class="hudson.tasks.LogRotator">
        <daysToKeep>30</daysToKeep>
        <numToKeep>50</numToKeep>
        <artifactDaysToKeep>-1</artifactDaysToKeep>
        <artifactNumToKeep>-1</artifactNumToKeep>
      </strategy>
    </jenkins.model.BuildDiscarderProperty>
    <job-metadata plugin="[email protected]">
      <values class="linked-list">
        <metadata-tree>
          <name>job-info</name>
          <parent class="job-metadata" reference="../../.."/>
          <generated>true</generated>
          <exposedToEnvironment>false</exposedToEnvironment>
          <children class="linked-list">
            <metadata-tree>
              <name>last-saved</name>
              <description></description>
              <parent class="metadata-tree" reference="../../.."/>
              <generated>true</generated>
              <exposedToEnvironment>false</exposedToEnvironment>
              <children class="linked-list">
                <metadata-date>
                  <name>time</name>
                  <description></description>
                  <parent class="metadata-tree" reference="../../.."/>
                  <generated>true</generated>
                  <exposedToEnvironment>false</exposedToEnvironment>
                  <value>
                    <time>1458097635464</time>
                    <timezone>Asia/Shanghai</timezone>
                  </value>
                  <checked>false</checked>
                </metadata-date>
                <metadata-tree>
                  <name>user</name>
                  <parent class="metadata-tree" reference="../../.."/>
                  <generated>true</generated>
                  <exposedToEnvironment>false</exposedToEnvironment>
                  <children class="linked-list">
                    <metadata-string>
                      <name>display-name</name>
                      <description></description>
                      <parent class="metadata-tree" reference="../../.."/>
                      <generated>true</generated>
                      <exposedToEnvironment>false</exposedToEnvironment>
                      <value>admin</value>
                    </metadata-string>
                    <metadata-string>
                      <name>full-name</name>
                      <description></description>
                      <parent class="metadata-tree" reference="../../.."/>
                      <generated>true</generated>
                      <exposedToEnvironment>false</exposedToEnvironment>
                      <value>admin</value>
                    </metadata-string>
                  </children>
                </metadata-tree>
              </children>
            </metadata-tree>
          </children>
        </metadata-tree>
      </values>
    </job-metadata>
  </properties>
  <scm class="hudson.scm.NullSCM"/>
  <scmCheckoutRetryCount>3</scmCheckoutRetryCount>
  <canRoam>true</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
    <hudson.tasks.Shell>
      <command>{docker_login} &amp;&amp; docker import {httpfilename} {imagename} &amp;&amp; docker push {imagename}
</command>
    </hudson.tasks.Shell>
  </builders>
  <publishers/>
  <buildWrappers>
    <hudson.plugins.ansicolor.AnsiColorBuildWrapper plugin="[email protected]">
      <colorMapName>xterm</colorMapName>
    </hudson.plugins.ansicolor.AnsiColorBuildWrapper>
  </buildWrappers>
</project>'''
        return s

    def getbasejob_config(self):
        s = '''<?xml version='1.0' encoding='UTF-8'?>
<project>
  <actions/>
  <description></description>
  <keepDependencies>false</keepDependencies>
  <properties>
    <com.tikal.hudson.plugins.notification.HudsonNotificationProperty plugin="[email protected]">
      <endpoints>
        <com.tikal.hudson.plugins.notification.Endpoint>
          <protocol>HTTP</protocol>
          <format>JSON</format>
          <url>http://10.1.39.60:8080/v1/hook</url>
          <event>completed</event>
          <timeout>30000</timeout>
          <loglines>0</loglines>
        </com.tikal.hudson.plugins.notification.Endpoint>
      </endpoints>
    </com.tikal.hudson.plugins.notification.HudsonNotificationProperty>
    <com.synopsys.arc.jenkins.plugins.ownership.jobs.JobOwnerJobProperty plugin="[email protected]"/>
    <hudson.plugins.heavy__job.HeavyJobProperty plugin="[email protected]">
      <weight>1</weight>
    </hudson.plugins.heavy__job.HeavyJobProperty>
    <jenkins.model.BuildDiscarderProperty>
      <strategy class="hudson.tasks.LogRotator">
        <daysToKeep>30</daysToKeep>
        <numToKeep>50</numToKeep>
        <artifactDaysToKeep>-1</artifactDaysToKeep>
        <artifactNumToKeep>-1</artifactNumToKeep>
      </strategy>
    </jenkins.model.BuildDiscarderProperty>
    <job-metadata plugin="[email protected]">
      <values class="linked-list">
        <metadata-tree>
          <name>job-info</name>
          <parent class="job-metadata" reference="../../.."/>
          <generated>true</generated>
          <exposedToEnvironment>false</exposedToEnvironment>
          <children class="linked-list">
            <metadata-tree>
              <name>last-saved</name>
              <description></description>
              <parent class="metadata-tree" reference="../../.."/>
              <generated>true</generated>
              <exposedToEnvironment>false</exposedToEnvironment>
              <children class="linked-list">
                <metadata-date>
                  <name>time</name>
                  <description></description>
                  <parent class="metadata-tree" reference="../../.."/>
                  <generated>true</generated>
                  <exposedToEnvironment>false</exposedToEnvironment>
                  <value>
                    <time>1457958794480</time>
                    <timezone>Asia/Shanghai</timezone>
                  </value>
                  <checked>false</checked>
                </metadata-date>
                <metadata-tree>
                  <name>user</name>
                  <parent class="metadata-tree" reference="../../.."/>
                  <generated>true</generated>
                  <exposedToEnvironment>false</exposedToEnvironment>
                  <children class="linked-list">
                    <metadata-string>
                      <name>display-name</name>
                      <description></description>
                      <parent class="metadata-tree" reference="../../.."/>
                      <generated>true</generated>
                      <exposedToEnvironment>false</exposedToEnvironment>
                      <value>admin</value>
                    </metadata-string>
                    <metadata-string>
                      <name>full-name</name>
                      <description></description>
                      <parent class="metadata-tree" reference="../../.."/>
                      <generated>true</generated>
                      <exposedToEnvironment>false</exposedToEnvironment>
                      <value>admin</value>
                    </metadata-string>
                  </children>
                </metadata-tree>
              </children>
            </metadata-tree>
          </children>
        </metadata-tree>
      </values>
    </job-metadata>
  </properties>
  <scm class="hudson.plugins.git.GitSCM" plugin="[email protected]">
    <configVersion>2</configVersion>
    <userRemoteConfigs>
      <hudson.plugins.git.UserRemoteConfig>
        <url>https://github.com/zhwenh/dockerfile-jdk-tomcat.git</url>
      </hudson.plugins.git.UserRemoteConfig>
    </userRemoteConfigs>
    <branches>
      <hudson.plugins.git.BranchSpec>
        <name>*/master</name>
      </hudson.plugins.git.BranchSpec>
    </branches>
    <doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
    <browser class="hudson.plugins.git.browser.GitLab">
      <url></url>
      <version>7.11</version>
    </browser>
    <submoduleCfg class="list"/>
    <extensions/>
  </scm>
  <scmCheckoutRetryCount>3</scmCheckoutRetryCount>
  <canRoam>true</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
    <hudson.tasks.Shell>
      <command>docker login -u admin -p admin123 -e [email protected] registry.test.com</command>
    </hudson.tasks.Shell>
    <com.cloudbees.dockerpublish.DockerBuilder plugin="[email protected]">
      <server plugin="[email protected]">
        <uri>unix:///var/run/docker.sock</uri>
      </server>
      <registry plugin="[email protected]">
        <url>http://registry.test.com/v2</url>
      </registry>
      <repoName>zhwenh/tomcat</repoName>
      <noCache>false</noCache>
      <forcePull>true</forcePull>
      <dockerfilePath>./Dockerfile</dockerfilePath>
      <skipBuild>false</skipBuild>
      <skipDecorate>false</skipDecorate>
      <repoTag>2.3.1</repoTag>
      <skipPush>false</skipPush>
      <createFingerprint>true</createFingerprint>
      <skipTagLatest>false</skipTagLatest>
      <buildAdditionalArgs></buildAdditionalArgs>
      <forceTag>true</forceTag>
    </com.cloudbees.dockerpublish.DockerBuilder>
  </builders>
  <publishers>
    <hudson.plugins.emailext.ExtendedEmailPublisher plugin="[email protected]">
      <recipientList>$DEFAULT_RECIPIENTS</recipientList>
      <configuredTriggers>
        <hudson.plugins.emailext.plugins.trigger.FailureTrigger>
          <email>
            <recipientList>$DEFAULT_RECIPIENTS</recipientList>
            <subject>$PROJECT_DEFAULT_SUBJECT</subject>
            <body>$PROJECT_DEFAULT_CONTENT</body>
            <recipientProviders>
              <hudson.plugins.emailext.plugins.recipients.DevelopersRecipientProvider/>
            </recipientProviders>
            <attachmentsPattern></attachmentsPattern>
            <attachBuildLog>false</attachBuildLog>
            <compressBuildLog>false</compressBuildLog>
            <replyTo>$PROJECT_DEFAULT_REPLYTO</replyTo>
            <contentType>project</contentType>
          </email>
        </hudson.plugins.emailext.plugins.trigger.FailureTrigger>
        <hudson.plugins.emailext.plugins.trigger.SuccessTrigger>
          <email>
            <recipientList>$DEFAULT_RECIPIENTS</recipientList>
            <subject>$PROJECT_DEFAULT_SUBJECT</subject>
            <body>$PROJECT_DEFAULT_CONTENT</body>
            <recipientProviders>
              <hudson.plugins.emailext.plugins.recipients.DevelopersRecipientProvider/>
            </recipientProviders>
            <attachmentsPattern></attachmentsPattern>
            <attachBuildLog>false</attachBuildLog>
            <compressBuildLog>false</compressBuildLog>
            <replyTo>$PROJECT_DEFAULT_REPLYTO</replyTo>
            <contentType>project</contentType>
          </email>
        </hudson.plugins.emailext.plugins.trigger.SuccessTrigger>
      </configuredTriggers>
      <contentType>default</contentType>
      <defaultSubject>$DEFAULT_SUBJECT</defaultSubject>
      <defaultContent>$DEFAULT_CONTENT</defaultContent>
      <attachmentsPattern></attachmentsPattern>
      <presendScript>$DEFAULT_PRESEND_SCRIPT</presendScript>
      <attachBuildLog>false</attachBuildLog>
      <compressBuildLog>false</compressBuildLog>
      <replyTo></replyTo>
      <saveOutput>false</saveOutput>
      <disabled>false</disabled>
    </hudson.plugins.emailext.ExtendedEmailPublisher>
  </publishers>
  <buildWrappers>
    <hudson.plugins.ansicolor.AnsiColorBuildWrapper plugin="[email protected]">
      <colorMapName>xterm</colorMapName>
    </hudson.plugins.ansicolor.AnsiColorBuildWrapper>
  </buildWrappers>
</project>'''

        return s

    @gen.coroutine
    def createbasejob(self):

        s = self.getbasejob_config()

        try:
            self.j.create_job(config.JENKINS_BASEJOB, s)
        except Exception as e:
            print e.message
            raise gen.Return(False)
        raise gen.Return(True)
Exemplo n.º 26
0
class JenkinsBot(BotPlugin):
    """Basic Err integration with Jenkins CI"""

    min_err_version = '1.2.1'

    # max_err_version = '4.0.3'

    def get_configuration_template(self):
        return CONFIG_TEMPLATE

    def configure(self, configuration):
        if configuration is not None and configuration != {}:
            config = dict(chain(CONFIG_TEMPLATE.items(),
                                configuration.items()))
        else:
            config = CONFIG_TEMPLATE
        super(JenkinsBot, self).configure(config)
        return

    def check_configuration(self, configuration):
        self.log.debug(configuration)
        for c, v in configuration.items():
            if c == 'URL':
                if not validators.url(v):
                    raise ValidationException(
                        'JENKINS_URL is not a well formed URL')
            elif c in ['USERNAME', 'PASSWORD', 'RECEIVE_NOTIFICATION']:
                if len(v) == 0 or not isinstance(v, str):
                    raise ValidationException(
                        "{} is a required string config setting".format(c))
            elif c in ['CHATROOMS_NOTIFICATION']:
                if not isinstance(v, tuple):
                    raise ValidationException(
                        "{} should be of type tuple".format(c))
        return

    def connect_to_jenkins(self):
        """Connect to a Jenkins instance using configuration."""
        self.log.debug('Connecting to Jenkins ({0})'.format(
            self.config['URL']))
        self.jenkins = Jenkins(url=self.config['URL'],
                               username=self.config['USERNAME'],
                               password=self.config['PASSWORD'])
        return

    def broadcast(self, mess):
        """Shortcut to broadcast a message to all elligible chatrooms."""
        chatrooms = (self.config['CHATROOMS_NOTIFICATION']
                     if self.config['CHATROOMS_NOTIFICATION'] else
                     self.bot_config.CHATROOM_PRESENCE)

        for room in chatrooms:
            self.send(self.build_identifier(room), mess)
        return

    @webhook(r'/jenkins/notification')
    def handle_notification(self, incoming_request):
        if not self.config['RECEIVE_NOTIFICATION']:
            return 'Notification handling is disabled.'

        self.log.debug(repr(incoming_request))
        self.broadcast(self.format_notification(incoming_request))
        return

    @botcmd
    def jenkins_list(self, mess, args):
        """List all jobs, optionally filter them using a search term."""
        self.connect_to_jenkins()
        return self.format_jobs([
            job for job in self.jenkins.get_jobs(folder_depth=None)
            if args.lower() in job['fullname'].lower()
        ])

    @botcmd
    def jenkins_running(self, mess, args):
        """List all running jobs."""
        self.connect_to_jenkins()

        jobs = [
            job for job in self.jenkins.get_jobs() if 'anime' in job['color']
        ]
        return self.format_running_jobs(jobs)

    @botcmd(split_args_with=None)
    def jenkins_param(self, mess, args):
        """List Parameters for a given job."""
        if len(args) == 0:
            return 'What Job would you like the parameters for?'

        self.connect_to_jenkins()

        job = self.jenkins.get_job_info(args[0])
        if job['actions'][1] != {}:
            job_param = job['actions'][1]['parameterDefinitions']
        elif job['actions'][0] != {}:
            job_param = job['actions'][0]['parameterDefinitions']
        else:
            job_param = []

        return self.format_params(job_param)

    @botcmd(split_args_with=None)
    def jenkins_build(self, mess, args):
        """Build a Jenkins Job with the given parameters
        Example: !jenkins build test_project FOO:bar
        """
        if len(args) == 0:  # No Job name
            return 'What job would you like to build?'

        self.connect_to_jenkins()
        params = self.build_parameters(args[1:])

        # Is it a parameterized job ?
        job = self.jenkins.get_job_info(args[0])
        if job['actions'][0] == {} and job['actions'][1] == {}:
            self.jenkins.build_job(args[0])
        else:
            self.jenkins.build_job(args[0], params)

        running_job = self.search_job(args[0])
        return 'Your job should begin shortly: {0}'.format(
            self.format_jobs(running_job))

    @botcmd(split_args_with=None)
    def build(self, mess, args):
        """Shortcut for jenkins_build"""
        return self.jenkins_build(mess, args)

    @botcmd
    def jenkins_unqueue(self, msg, args):
        """Cancel a queued job.
        Example !jenkins unqueue foo
        """
        self.connect_to_jenkins()

        try:
            queue = self.jenkins.get_queue_info()

            job = next((job for job in queue
                        if job['task']['name'].lower() == args.lower()), None)

            if job:
                self.jenkins.cancel_queue(job['id'])
                return 'Unqueued job {0}'.format(job['task']['name'])
            else:
                return 'Could not find job {0}, but found the following: {1}'.format(
                    args, ', '.join(job['task']['name'] for job in queue))
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

    @botcmd(split_args_with=None)
    def jenkins_createjob(self, mess, args):
        """Create a Jenkins Job.
        Example: !jenkins createjob pipeline foo [email protected]:foo/bar.git
        """
        if len(args) < 2:  # No Job type or name
            return 'Oops, I need a type and a name for your new job.'

        if args[0] not in ('pipeline', 'multibranch'):
            return 'I\'m sorry, I can only create `pipeline` and \
                    `multibranch` jobs.'

        self.connect_to_jenkins()

        try:
            if args[0] == 'pipeline':
                self.jenkins.create_job(
                    args[1],
                    JENKINS_JOB_TEMPLATE_PIPELINE.format(repository=args[2]))

            elif args[0] == 'multibranch':
                repository = args[2].rsplit('/', maxsplit=2)[-2:]

                self.jenkins.create_job(
                    args[1],
                    JENKINS_JOB_TEMPLATE_MULTIBRANCH.format(
                        repo_owner=repository[0].split(':')[-1],
                        repo_name=repository[1].strip('.git')))
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)
        return 'Your job has been created: {0}/job/{1}'.format(
            self.config['URL'], args[1])

    @botcmd(split_args_with=None)
    def jenkins_deletejob(self, mess, args):
        """Delete a Jenkins Job.
        Example: !jenkins deletejob foo
        """
        if len(args) < 1:  # No job name
            return 'Oops, I need the name of the job you want me to delete.'

        self.connect_to_jenkins()

        try:
            self.jenkins.delete_job(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your job has been deleted.'

    @botcmd(split_args_with=None)
    def jenkins_enablejob(self, mess, args):
        """Enable a Jenkins Job.
        Example: !jenkins enablejob foo
        """
        if len(args) < 1:  # No job name
            return 'Oops, I need the name of the job you want me to enable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.enable_job(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your job has been enabled.'

    @botcmd(split_args_with=None)
    def jenkins_disablejob(self, mess, args):
        """Disable a Jenkins Job.
        Example: !jenkins disablejob foo
        """
        if len(args) < 1:  # No job name
            return 'Oops, I need the name of the job you want me to disable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.disable_job(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your job has been disabled.'

    @botcmd(split_args_with=None)
    def jenkins_createnode(self, mess, args):
        """Create a Jenkins Node with a JNLP Launcher with optionnal labels.
        Example: !jenkins createnode runner-foo-laptop /home/foo # without labels
        Example: !jenkins createnode runner-bar-laptop /home/bar linux docker # with labels
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need a name and a working dir for your new node.'

        self.connect_to_jenkins()

        try:
            self.jenkins.create_node(name=args[0],
                                     remoteFS=args[1],
                                     labels=' '.join(args[2:]),
                                     exclusive=True,
                                     launcher=LAUNCHER_JNLP)
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been created: {0}/computer/{1}'.format(
            self.config['URL'], args[0])

    @botcmd(split_args_with=None)
    def jenkins_deletenode(self, mess, args):
        """Delete a Jenkins Node.
        Example: !jenkins deletenode runner-foo-laptop
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need the name of the node you want me to delete.'

        self.connect_to_jenkins()

        try:
            self.jenkins.delete_node(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been deleted.'

    @botcmd(split_args_with=None)
    def jenkins_enablenode(self, mess, args):
        """Enable a Jenkins Node.
        Example: !jenkins enablenode runner-foo-laptop
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need the name of the node you want me to enable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.enable_node(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been enabled.'

    @botcmd(split_args_with=None)
    def jenkins_disablenode(self, mess, args):
        """Disable a Jenkins Node.
        Example: !jenkins disablenode runner-foo-laptop
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need the name of the node you want me to disable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.disable_node(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been disabled.'

    def search_job(self, search_term):
        self.log.debug('Querying Jenkins for job "{0}"'.format(search_term))
        return [
            job for job in self.jenkins.get_jobs(folder_depth=None)
            if search_term.lower() == job['fullname'].lower()
        ]

    def format_running_jobs(self, jobs):
        if len(jobs) == 0:
            return 'No running jobs.'

        jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs]
        return '\n\n'.join([
            '%s (%s)\n%s' % (job['name'], job['lastBuild']['url'],
                             job['healthReport'][0]['description'])
            for job in jobs_info
        ]).strip()

    @staticmethod
    def format_jobs(jobs):
        if len(jobs) == 0:
            return 'No jobs found.'

        max_length = max([len(job['fullname']) for job in jobs])
        return '\n'.join([
            '%s (%s)' % (job['fullname'].ljust(max_length), job['url'])
            for job in jobs
        ]).strip()

    @staticmethod
    def format_params(job):
        """Format job parameters."""
        if len(job) == 0:
            return 'This job is not parameterized.'
        PARAM_TEMPLATE = Template("""{% for p in params %}Type: {{p.type}}
Description: {{p.description}}
Default Value: {{p.defaultParameterValue.value}}
Parameter Name: {{p.name}}

{% endfor %}""")
        return PARAM_TEMPLATE.render({'params': job})

    @staticmethod
    def format_notification(body):
        body['fullname'] = body.get('fullname', body['name'])
        NOTIFICATION_TEMPLATE = Template("""Build #{{build.number}} \
{{build.status}} for Job {{fullname}} ({{build.full_url}})
{% if build.scm %}Based on {{build.scm.url}}/commit/{{build.scm.commit}} \
({{build.scm.branch}}){% endif %}""")
        return NOTIFICATION_TEMPLATE.render(body)

    @staticmethod
    def build_parameters(params):
        if len(params) > 0:
            return {
                param.split(':')[0]: param.split(':')[1]
                for param in params
            }
        return {'': ''}
Exemplo n.º 27
0
class Job():
    def __init__(self, job_name):
        self.j = Jenkins(configuration['jenkinsUrl'],
                         configuration['jenkinsUser'],
                         configuration['jenkinsPass'])
        self.j._session.verify = False
        self.job_name = job_name

    @property
    def extra_columns(self):
        return [
            'userId', 'userName', 'currentStage', 'status', 'teardownStatus'
        ]

    @property
    def valid_job_name(self):
        if '-' in self.job_name:
            return self.job_name.replace('-', '_')
        else:
            return self.job_name

    @property
    def parameters_collection(self):
        return self.get_parameters_names() + self.get_meta_parameters(
        ) + self.get_test_parameters() + self.extra_columns

    def get_parameters(self):
        try:
            job_info = self.j.get_job_info(name=self.job_name)
            to_return = dict(job_info['property'][0])['parameterDefinitions']
            return to_return
        except:
            raise Exception(
                "Could not find parameters, are you sure this is the name of the job and it is Parameterized?"
            )

    def get_parameters_names(self):
        names = []
        for param in self.get_parameters():
            names.append(param['name'])

        return names

    def get_parameters_query(self):
        try:
            parameters = self.get_parameters()
            return {parameter['name']: "TEXT" for parameter in parameters}
        except:
            raise Exception(
                f"Something went wrong with receiving parameters from the job {self.job_name}. Are you sure this job exists?"
            )

    def get_meta_parameters(self):
        return ['number', 'building', 'buildDuration', 'url']

    def get_meta_query(self):
        # number going to be in the column as INT type and not text
        meta = {}
        meta['number'] = 'INT'
        meta['building'] = 'BOOLEAN'
        meta['buildDuration'] = 'TEXT'
        meta['url'] = 'TEXT'

        return meta

    def get_test_parameters(self):
        return [
            'testDuration', 'testCount', 'failCount', 'passCount', 'skipCount',
            "successRate"
        ]

    def get_test_query(self):
        meta = {}
        keys = self.get_test_parameters()
        for key in keys:
            if 'Count' in key or "successRate" in key:
                meta[key] = 'INT'
            else:
                meta[key] = 'TEXT'

        return meta

    def get_extra_columns_query(self):
        meta = {}
        keys = self.extra_columns
        for key in keys:
            meta[key] = 'TEXT'

        return meta

    def parameters_query_column(self):
        columns_query = '\n('

        collection = self.get_parameters_query()
        collection.update(self.get_meta_query())
        collection.update(self.get_test_query())
        collection.update(self.get_extra_columns_query())

        for column, type in collection.items():
            columns_query += f"{column}         {type}   NULL"

            if not list(collection.items())[-1] == (column, type):
                columns_query += ',\n'

        columns_query += ');'

        print(columns_query)
        return columns_query

    def create_table_query(self):
        ########
        #Looking for creating a valid job name because sql query is not ok with dashes
        ########
        query = f'''CREATE TABLE {self.valid_job_name}{self.parameters_query_column()}'''
        return query
Exemplo n.º 28
0
class TaskBuilder:
    def __init__(self, jenkinsURL):
        self.j = Jenkins(jenkinsURL)
        self.jobName = ""
        #with open("config.xml") as file:
        with open("./builds/config/job/config.xml") as file:
            self.templateConfig = file.read()
        self.template = Template(unicode(self.templateConfig))

    def set_new_config(self, **params):
        self.newConfig = self.template.render(repos=params['repos'],
                                              description=params['repos'])

    def add_build(self, **params):
        self.set_job_name(**params)
        self.set_new_config(**params)

        if self.j.job_exists(self.jobName):
            self.do_build(**params)
        else:

            self.j.create_job(self.jobName, self.newConfig)
            self.do_build(**params)

    def do_build(self, **params):
        self.set_job_name(**params)
        self.set_new_config(**params)

        self.j.enable_job(self.jobName)
        self.j.build_job(self.jobName, {'branch': params['branch'], 'version': params['version'], 'author': params['author'], \
          'styleguide_repo': params['styleguide_repo'], 'styleguide_branch': params['styleguide_branch'], 'sidecar_repo': params['sidecar_repo'], \
          'sidecar_branch': params['sidecar_branch'], 'package_list': params['package_list'], 'upgrade_package': params['upgrade_package'], \
          'latin': params['latin'], 'demo_data': params['demo_data']} )

    def set_job_name(self, **params):
        buildUtil = BuildUtil()
        self.jobName = buildUtil.get_job_name(repos=params['repos'])

    def get_build_status(self, jobName):
        #job_info = self.j.get_job_info(self.jobName)
        #return build_status
        color_status = {
            "aborted": "Aborted",
            "red": "Failed",
            "blue": "Succcess"
        }
        if jobName == "":
            print "Have to specify job name"
            return False
        else:
            if self.j.job_exists(jobName):
                #Job exist in the job list
                job_info = self.j.get_job_info(jobName)

                if color_status.has_key(job_info['color']):
                    return color_status[job_info['color']]
                else:
                    return 'Running'
            else:
                print "Have to specify a validate job name"
                return False

    def get_job_name(self):
        return self.jobName

    def stop_jenkins_job(self, job_url):
        """
    1. stop one job
    """
        stop_job_url = job_url + 'lastBuild/stop'
        try:
            ss = urllib2.urlopen(stop_job_url, None, 30).read()
            ss.close()
        except:
            return '{}'

    def stop_jenkins_jobs(self, jobName):
        """
    1. find all the sub job
    2. stop all the running sub job
    3. stop current job
    """
        if self.j.job_exists(jobName):
            for x in self.j.get_job_info(jobName)['downstreamProjects']:
                if self.get_build_status(x['name']) == 'Running':
                    self.stop_jenkins_job(x['url'])
            self.stop_jenkins_job(self.j.get_job_info(jobName)['url'])
        else:
            pass
Exemplo n.º 29
0
from jenkins import Jenkins

job_settings = {
    'DEPLOY_TO': 'feature1.dev.roundme.com',
    'FRONTEND_BRANCH': '1.6.1',
    'BACKEND_BRANCH': '1.6.1',
    'RUN_TEST': False,
    'DEPLOY_REPO_BRANCH': 'master',
    'NPM_ARGS': 'production',
    'GRUNT_ARGS': 'testing',
    'DEPLOY_TO_S3': False,
    'MIGRATE': False,
    'ENV': 'feature'
}

server = Jenkins('http://234234', username='******', password='******')

# serverstring
print(server)
user = server.get_whoami()
print(user)
job = server.get_job_config('Roundme.Full.Build')
print(job)
server.build_job('Roundme.Full.Build', job_settings)
last_build_number = server.get_job_info(
    'Roundme.Full.Build')['lastCompletedBuild']['number']
build_info = server.get_build_info('Roundme.Full.Build', last_build_number)
print(build_info)
Exemplo n.º 30
0
class JenkinsBot(BotPlugin):
    """Basic Err integration with Jenkins CI"""

    min_err_version = '1.2.1'
    # max_err_version = '4.0.3'

    def get_configuration_template(self):
        return CONFIG_TEMPLATE

    def configure(self, configuration):
        if configuration is not None and configuration != {}:
            config = dict(chain(CONFIG_TEMPLATE.items(),
                                configuration.items()))
        else:
            config = CONFIG_TEMPLATE
        super(JenkinsBot, self).configure(config)
        return

    def check_configuration(self, configuration):
        self.log.debug(configuration)
        for c, v in configuration.items():
            if c == 'URL':
                if not validators.url(v):
                    raise ValidationException('JENKINS_URL is not a well formed URL')
            elif c in ['USERNAME', 'PASSWORD', 'RECEIVE_NOTIFICATION']:
                if len(v) == 0 or not isinstance(v, str):
                    raise ValidationException("{} is a required string config setting".format(c))
            elif c in ['CHATROOMS_NOTIFICATION']:
                if not isinstance(v, tuple):
                    raise ValidationException("{} should be of type tuple".format(c))
        return

    def connect_to_jenkins(self):
        """Connect to a Jenkins instance using configuration."""
        self.log.debug('Connecting to Jenkins ({0})'.format(
            self.config['URL']))
        self.jenkins = Jenkins(url=self.config['URL'],
                               username=self.config['USERNAME'],
                               password=self.config['PASSWORD'])
        return

    def broadcast(self, mess):
        """Shortcut to broadcast a message to all elligible chatrooms."""
        chatrooms = (self.config['CHATROOMS_NOTIFICATION']
                     if self.config['CHATROOMS_NOTIFICATION']
                     else self.bot_config.CHATROOM_PRESENCE)

        for room in chatrooms:
            self.send(self.build_identifier(room), mess)
        return

    @webhook(r'/jenkins/notification')
    def handle_notification(self, incoming_request):
        if not self.config['RECEIVE_NOTIFICATION']:
            return 'Notification handling is disabled.'

        self.log.debug(repr(incoming_request))
        self.broadcast(self.format_notification(incoming_request))
        return

    @botcmd
    def jenkins_list(self, mess, args):
        """List all jobs, optionally filter them using a search term."""
        self.connect_to_jenkins()
        return self.format_jobs([job for job in self.jenkins.get_jobs(folder_depth=None)
            if args.lower() in job['fullname'].lower()])

    @botcmd
    def jenkins_running(self, mess, args):
        """List all running jobs."""
        self.connect_to_jenkins()

        jobs = [job for job in self.jenkins.get_jobs()
                if 'anime' in job['color']]
        return self.format_running_jobs(jobs)

    @botcmd(split_args_with=None)
    def jenkins_param(self, mess, args):
        """List Parameters for a given job."""
        if len(args) == 0:
            return 'What Job would you like the parameters for?'

        self.connect_to_jenkins()

        job = self.jenkins.get_job_info(args[0])
        if job['actions'][1] != {}:
            job_param = job['actions'][1]['parameterDefinitions']
        elif job['actions'][0] != {}:
            job_param = job['actions'][0]['parameterDefinitions']
        else:
            job_param = []

        return self.format_params(job_param)

    @botcmd(split_args_with=None)
    def jenkins_build(self, mess, args):
        """Build a Jenkins Job with the given parameters
        Example: !jenkins build test_project FOO:bar
        """
        if len(args) == 0:  # No Job name
            return 'What job would you like to build?'

        self.connect_to_jenkins()
        params = self.build_parameters(args[1:])

        # Is it a parameterized job ?
        job = self.jenkins.get_job_info(args[0])
        if job['actions'][0] == {} and job['actions'][1] == {}:
            self.jenkins.build_job(args[0])
        else:
            self.jenkins.build_job(args[0], params)

        running_job = self.search_job(args[0])
        return 'Your job should begin shortly: {0}'.format(
            self.format_jobs(running_job))

    @botcmd(split_args_with=None)
    def build(self, mess, args):
        """Shortcut for jenkins_build"""
        return self.jenkins_build(mess, args)

    @botcmd
    def jenkins_unqueue(self, msg, args):
        """Cancel a queued job.
        Example !jenkins unqueue foo
        """
        self.connect_to_jenkins()

        try:
            queue = self.jenkins.get_queue_info()

            job = next((job for job in queue if job['task']['name'].lower() == args.lower()), None)

            if job:
                self.jenkins.cancel_queue(job['id'])
                return 'Unqueued job {0}'.format(job['task']['name'])
            else:
                return 'Could not find job {0}, but found the following: {1}'.format(
                    args, ', '.join(job['task']['name'] for job in queue))
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

    @botcmd(split_args_with=None)
    def jenkins_createjob(self, mess, args):
        """Create a Jenkins Job.
        Example: !jenkins createjob pipeline foo [email protected]:foo/bar.git
        """
        if len(args) < 2:  # No Job type or name
            return 'Oops, I need a type and a name for your new job.'

        if args[0] not in ('pipeline', 'multibranch'):
            return 'I\'m sorry, I can only create `pipeline` and \
                    `multibranch` jobs.'

        self.connect_to_jenkins()

        try:
            if args[0] == 'pipeline':
                self.jenkins.create_job(
                    args[1],
                    JENKINS_JOB_TEMPLATE_PIPELINE.format(repository=args[2]))

            elif args[0] == 'multibranch':
                repository = args[2].rsplit('/', maxsplit=2)[-2:]

                self.jenkins.create_job(
                    args[1],
                    JENKINS_JOB_TEMPLATE_MULTIBRANCH.format(
                        repo_owner=repository[0].split(':')[-1],
                        repo_name=repository[1].strip('.git')))
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)
        return 'Your job has been created: {0}/job/{1}'.format(
            self.config['URL'], args[1])

    @botcmd(split_args_with=None)
    def jenkins_deletejob(self, mess, args):
        """Delete a Jenkins Job.
        Example: !jenkins deletejob foo
        """
        if len(args) < 1:  # No job name
            return 'Oops, I need the name of the job you want me to delete.'

        self.connect_to_jenkins()

        try:
            self.jenkins.delete_job(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your job has been deleted.'

    @botcmd(split_args_with=None)
    def jenkins_enablejob(self, mess, args):
        """Enable a Jenkins Job.
        Example: !jenkins enablejob foo
        """
        if len(args) < 1:  # No job name
            return 'Oops, I need the name of the job you want me to enable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.enable_job(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your job has been enabled.'

    @botcmd(split_args_with=None)
    def jenkins_disablejob(self, mess, args):
        """Disable a Jenkins Job.
        Example: !jenkins disablejob foo
        """
        if len(args) < 1:  # No job name
            return 'Oops, I need the name of the job you want me to disable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.disable_job(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your job has been disabled.'

    @botcmd(split_args_with=None)
    def jenkins_createnode(self, mess, args):
        """Create a Jenkins Node with a JNLP Launcher with optionnal labels.
        Example: !jenkins createnode runner-foo-laptop /home/foo # without labels
        Example: !jenkins createnode runner-bar-laptop /home/bar linux docker # with labels
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need a name and a working dir for your new node.'

        self.connect_to_jenkins()

        try:
            self.jenkins.create_node(
                name=args[0],
                remoteFS=args[1],
                labels=' '.join(args[2:]),
                exclusive=True,
                launcher=LAUNCHER_JNLP)
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been created: {0}/computer/{1}'.format(
            self.config['URL'], args[0])

    @botcmd(split_args_with=None)
    def jenkins_deletenode(self, mess, args):
        """Delete a Jenkins Node.
        Example: !jenkins deletenode runner-foo-laptop
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need the name of the node you want me to delete.'

        self.connect_to_jenkins()

        try:
            self.jenkins.delete_node(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been deleted.'

    @botcmd(split_args_with=None)
    def jenkins_enablenode(self, mess, args):
        """Enable a Jenkins Node.
        Example: !jenkins enablenode runner-foo-laptop
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need the name of the node you want me to enable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.enable_node(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been enabled.'

    @botcmd(split_args_with=None)
    def jenkins_disablenode(self, mess, args):
        """Disable a Jenkins Node.
        Example: !jenkins disablenode runner-foo-laptop
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need the name of the node you want me to disable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.disable_node(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been disabled.'

    def search_job(self, search_term):
        self.log.debug('Querying Jenkins for job "{0}"'.format(search_term))
        return [job for job in self.jenkins.get_jobs(folder_depth=None)
                if search_term.lower() == job['fullname'].lower()]

    def format_running_jobs(self, jobs):
        if len(jobs) == 0:
            return 'No running jobs.'

        jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs]
        return '\n\n'.join(['%s (%s)\n%s' % (
            job['name'],
            job['lastBuild']['url'],
            job['healthReport'][0]['description'])
                            for job in jobs_info]).strip()

    @staticmethod
    def format_jobs(jobs):
        if len(jobs) == 0:
            return 'No jobs found.'

        max_length = max([len(job['fullname']) for job in jobs])
        return '\n'.join(
            ['%s (%s)' % (job['fullname'].ljust(max_length), job['url'])
             for job in jobs]).strip()

    @staticmethod
    def format_params(job):
        """Format job parameters."""
        if len(job) == 0:
            return 'This job is not parameterized.'
        PARAM_TEMPLATE = Template("""{% for p in params %}Type: {{p.type}}
Description: {{p.description}}
Default Value: {{p.defaultParameterValue.value}}
Parameter Name: {{p.name}}

{% endfor %}""")
        return PARAM_TEMPLATE.render({'params': job})

    @staticmethod
    def format_notification(body):
        body['fullname'] = body.get('fullname', body['name'])
        NOTIFICATION_TEMPLATE = Template("""Build #{{build.number}} \
{{build.status}} for Job {{fullname}} ({{build.full_url}})
{% if build.scm %}Based on {{build.scm.url}}/commit/{{build.scm.commit}} \
({{build.scm.branch}}){% endif %}""")
        return NOTIFICATION_TEMPLATE.render(body)

    @staticmethod
    def build_parameters(params):
        if len(params) > 0:
            return {param.split(':')[0]: param.split(':')[1]
                    for param in params}
        return {'': ''}
Exemplo n.º 31
0
# -*- coding: utf-8 -*-
# @Time    : 2019-07-26 20:23
# @Author  : Eylaine
# @File    : __init__.py

from jenkins import Jenkins

from settings import JENKINS_URL as URL
from settings import JENKINS_PASSWORD as PASSWORD
from settings import JENKINS_USERNAME as USERNAME
from settings import JENKINS_JOB_NAME as JOB_NAME
"""python-jenkins模块的使用和常用方法"""
jenkins = Jenkins(URL, USERNAME, PASSWORD)

# 获取所有的jobs
all_jobs = jenkins.get_all_jobs()

# 根据job name获取info,返回json
job_info = jenkins.get_job_info(JOB_NAME)

# 最后一次build的信息,包含num和url
last_build = job_info["lastBuild"]
# 最后一次build的number,int类型
NUMBER = last_build["number"]

build_info = jenkins.get_build_info(JOB_NAME, NUMBER)
info = jenkins.get_info()

# 运行日志
console_text = jenkins.get_build_console_output(JOB_NAME, NUMBER)