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