示例#1
0
文件: jenkins.py 项目: edx/tubular
def trigger_build(base_url,
                  user_name,
                  user_token,
                  job_name,
                  job_token,
                  job_cause=None,
                  job_params=None,
                  timeout=60 * 30):
    u"""
    Trigger a jenkins job/project (note that jenkins uses these terms interchangeably)

    Args:
        base_url (str): The base URL for the jenkins server, e.g. https://test-jenkins.testeng.edx.org
        user_name (str): The jenkins username
        user_token (str): API token for the user. Available at {base_url}/user/{user_name)/configure
        job_name (str): The Jenkins job name, e.g. test-project
        job_token (str): Jobs must be configured with the option "Trigger builds remotely" selected.
            Under this option, you must provide an authorization token (configured in the job)
            in the form of a string so that only those who know it would be able to remotely
            trigger this project's builds.
        job_cause (str): Text that will be included in the recorded build cause
        job_params (set of tuples): Parameter names and their values to pass to the job
        timeout (int): The maximum number of seconds to wait for the jenkins build to complete (measured
            from when the job is triggered.)

    Returns:
        A the status of the build that was triggered

    Raises:
        BackendError: if the Jenkins job could not be triggered successfully
    """
    @backoff.on_predicate(
        backoff.constant,
        interval=60,
        max_tries=timeout / 60 + 1,
        on_giveup=_poll_giveup,
        # We aren't worried about concurrent access, so turn off jitter
        jitter=None,
    )
    def poll_build_for_result(build):
        u"""
        Poll for the build running, with exponential backoff, capped to ``timeout`` seconds.
        The on_predicate decorator is used to retry when the return value
        of the target function is True.
        """
        return not build.is_running()

    # Create a dict with key/value pairs from the job_params
    # that were passed in like this:  --param FOO bar --param BAZ biz
    # These will get passed to the job as string parameters like this:
    # {u'FOO': u'bar', u'BAX': u'biz'}
    request_params = {}
    for param in job_params:
        request_params[param[0]] = param[1]

    # Contact jenkins, log in, and get the base data on the system.
    try:
        crumb_requester = CrumbRequester(baseurl=base_url,
                                         username=user_name,
                                         password=user_token,
                                         ssl_verify=True)
        jenkins = Jenkins(base_url,
                          username=user_name,
                          password=user_token,
                          requester=crumb_requester)
    except (JenkinsAPIException, HTTPError) as err:
        raise BackendError(str(err))

    if not jenkins.has_job(job_name):
        msg = u'Job not found: {}.'.format(job_name)
        msg += u' Verify that you have permissions for the job and double check the spelling of its name.'
        raise BackendError(msg)

    # This will start the job and will return a QueueItem object which can be used to get build results
    job = jenkins[job_name]
    queue_item = job.invoke(securitytoken=job_token,
                            build_params=request_params,
                            cause=job_cause)
    LOG.info(u'Added item to jenkins. Server: {} Job: {} '.format(
        jenkins.base_server_url(), queue_item))

    # Block this script until we are through the queue and the job has begun to build.
    queue_item.block_until_building()
    build = queue_item.get_build()
    LOG.info(u'Created build {}'.format(build))
    LOG.info(u'See {}'.format(build.baseurl))

    # Now block until you get a result back from the build.
    poll_build_for_result(build)

    # Update the build's internal state, so that the final status is available
    build.poll()

    status = build.get_status()
    LOG.info(u'Build status: {status}'.format(status=status))
    return status