text: #!/usr/bin/env python
  
  # Licensed to the Apache Software Foundation (ASF) under one
  # or more contributor license agreements.  See the NOTICE file
  # distributed with this work for additional information
  # regarding copyright ownership.  The ASF licenses this file
  # to you under the Apache License, Version 2.0 (the
  # "License"); you may not use this file except in compliance
  # with the License.  You may obtain a copy of the License at
  #
  #   http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing,
  # software distributed under the License is distributed on an
  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  # KIND, either express or implied.  See the License for the
  # specific language governing permissions and limitations
  # under the License.
  
  
  from ConfigParser import ConfigParser
  from jenkinsapi import api, jenkins, job
  from time import sleep as delay
  import jenkinsapi
  import logging
  import os
  
  class BuildGenerator(object):
      """
      1. Create a job on Hudson/Jenkins 
      2. Poll for job status
      3. Fetch latest successful job
      4. Resolve Job to Repo URL/fetch artifact
      """
      def __init__(self, username=None, passwd=None, url="http://hudson.lab.vmops.com", job='CloudStack-PRIVATE'):
          #TODO: Change the username to "vogon" for automation
          self.hudsonurl = url
          self.tarball = None
          self.build_number = 0
          #self.jenkinsurl = "http://jenkins.jobclient.org"
          if username and passwd:
              self.username = username
              self.password = passwd
          else:
              logging.warning("no username given, logging in with default creds")
              self.username = "marvin"
              self.password = "marvin"
  
          try:
              j = jenkins.Jenkins(self.hudsonurl, self.username, self.password)
              self.jobclient = j.get_job(job)
          except Exception, e:
              logging.error("Failed to login to Hudson")
              raise e
          else:
              logging.debug("successfully logged into hudson instance %s \
                            using username, passwd : %s, %s" \
                            %(self.hudsonurl, self.username, self.password))
  
      def readBuildConfiguration(self, cfg_file):
          cfg = ConfigParser()
          cfg.optionxform = str
          if cfg.read(cfg_file):
              logging.debug("Using config file found at %s"%cfg_file)
              self.config = cfg
          else:
              raise IOError("Cannot find file %s"%cfg_file)
  
      def parseConfigParams(self):
          #TODO: passing a config file should be allowed as cmd line args
          params = {}
          if self.config:
              logging.debug("build params found:")
              for k,v in dict(self.config.items('build_params')).iteritems():
                  logging.debug("%s : %s"%(k,v))
              return dict(self.config.items('build_params'))
          else:
              logging.debug("build config not found")
              raise ValueError("Build configuration was not initialized")
  
      def build(self, wait=20):
          if self.config and self.jobclient:
              while self.jobclient.is_queued_or_running():
                  logging.debug("Waiting  %ss for running/queued build to complete"%wait)
                  delay(wait)
                  
              self.jobclient.invoke(params=self.parseConfigParams())
              self.build_number = self.jobclient.get_last_buildnumber()
              self.paramlist = self.parseConfigParams()
              logging.info("Started build : %d"%self.jobclient.get_last_buildnumber())
              
              while self.jobclient.is_running():
                  logging.debug("Polling build status in %ss"%wait)
                  delay(wait)
              
              logging.info("Completed build : %d"%self.jobclient.get_last_buildnumber())
              logging.debug("Last Good Build : %d, Last Build : %d, Our Build : \
                            %d"%(self.jobclient.get_last_good_buildnumber(), \
                                  self.jobclient.get_last_buildnumber(), \
                                  self.build_number))
              if self.jobclient.get_last_good_buildnumber() == self.build_number:
                  return self.build_number
              else: #lastGoodBuild != ourBuild
                  our_build = self.getBuildWithNumber(self.build_number)
                  if our_build is not None and our_build.get_status() == 'SUCCESS':
                      logging.debug("Our builds' %d status %s"%(self.build_number,
                                                                our_build.get_status()))
                      return self.build_number
                  else:
                      logging.debug("Our builds' %d status %s"%(self.build_number,
                                                                our_build.get_status()))
                      return 0
  
      def getLastGoodBuild(self):
          return self.jobclient.get_build(self.build_number)
      
      def getBuildWithNumber(self, number):
          if number > 0:
              bld = self.jobclient.get_build(number)
              self.build_number = number
              self.paramlist = self.getBuildParamList(bld)
              return bld
  
      def getBuildParamValue(self, name):
          return self.paramlist[name]
  
      def getTarballName(self):
          if self.tarball is not None:
              return self.tarball
          else:
              self.resolveRepoPath()
              return self.getTarballName()
      
      def getArtifacts(self):
          artifact_dict = self.getLastGoodBuild().get_artifact_dict()
          if artifact_dict is not None:
              return artifact_dict
  
      def sift(self, dic):
          return dic['name'], dic['value']
      
      def getBuildParamList(self, bld):
          params = bld.get_actions()['parameters']
          return dict(map(self.sift, params))
          
      def resolveRepoPath(self):
              tarball_list = ['CloudStack-' , 
                         self.getBuildParamValue('PACKAGE_VERSION') , 
                         '-0.', str(self.build_number) , '-' , 
                         self.getBuildParamValue('DO_DISTRO_PACKAGES') ,  
                         '.tar.gz'] 
  
              self.tarball = ''.join(tarball_list)
  
              path = os.path.join('yumrepo.lab.vmops.com', 'releases', 'rhel', \
                                  self.getBuildParamValue('DO_DISTRO_PACKAGES').strip('rhel'), \
                                  self.getBuildParamValue('PUSH_TO_REPO'), \
                                  self.tarball)
              logging.debug("resolved last good build generated by us to: %s"%path)
              return path
          
  if __name__ == '__main__':
  #    hudson = BuildGenerator(job="marvin")
  #    hudson.readBuildConfiguration('build.cfg')
  #    hudson.build()
  
       hudson = BuildGenerator("CloudStack-PRIVATE")
       hudson.readBuildConfiguration('build.cfg')
       hudson.build(wait=60)
  #     hudson.getBuildWithNumber(2586)
  