def run_test_on_jita(
    self, cluster, commit_id=None, build_url=None, job_ids_list=None,
    index=None, hypervisor=None, hypervisor_version=None, branch=None,
    input_type="build_url", build_type="opt", test=None, username=None,
    test_upgrade=None, base_commit=None):

    # NEEDS CHANGE
    if not hypervisor:
      hypervisor = FLAGS.hypervisor 
    if not hypervisor_version:
      hypervisor_version = FLAGS.hypervisor_version
    if not branch:
      branch = FLAGS.branch
    if not test:
      test = FLAGS.test_name
    if not username:
      username = USERNAME
    test_framework = FLAGS.test_framework

    if test_upgrade is None:
      test_upgrade = FLAGS.upgrade_test
      base_commit=FLAGS.upgrade_base_commit

    if test_upgrade:
      phoenix_commit = base_commit
    else:
      phoenix_commit = commit_id

    if not self.image_cluster( cluster, phoenix_commit, build_url, USERNAME,
                              hypervisor, hypervisor_version, branch,
                              build_type):
      job_ids_list[index] = False
      ERROR("Imaging failed on cluster %s" % cluster)
      return False

    jita = JitaRest()
    jita_test = jita.get_test(test,test_framework)
    if test_upgrade:
      svm_installer_url = self.get_svm_installer(commit_id, branch, build_type)
      INFO("Found build %s " % svm_installer_url)
      if not svm_installer_url:
        return False

      args_map = {"target_rel" : svm_installer_url}
    else:
      args_map = None

    INFO("Going to submit task for commit id: %s" % commit_id)
    response_obj = jita.submit_task(
      cluster, commit_id, branch, [jita_test.get_id()],
      test_framework=test_framework, label="auto_bisector", args_map=args_map)

    if response_obj.is_success():
      job_ids_list[index] = response_obj.get_task_id()
      return True
    else:
      ERROR("Task submit failed: %s" % response_obj.get_message())
      return False
  def get_svm_installer(self, commit_id, branch, build_type):
    """
    Get the build location for th given commit id and branch.
    """  
    INFO("Getting installer for commit %s" % commit_id)
    filer = FLAGS.lab
    jita=JitaRest()
    build_url = jita.get_build_url(commit_id, build_type, filer)
    if build_url:
      INFO("Found build %s" % build_url)
      return build_url

    INFO("Checking if build is in progress")
    build_task_id = jita.check_build_in_progress(commit_id, branch, build_type,
                                                 filer)

    if build_task_id:
      status = jita.get_build_task(build_task_id).get_status()

    if not build_task_id or status in ["failed", "aborted", "skipped"]:
      INFO("Could not find an existing build. Hence requesting build")
      res = jita.request_build(commit_id, branch, build_type, filer)
      if res.get_status():
        build_task_id = res.get_build_task_id()
      else:
        ERROR("Build request for commit id %s failed" % commit_id)
        return False

    if self.wait_for_build_to_complete(build_task_id):
      return jita.get_build_url(commit_id, build_type, filer)

    return False
  def wait_for_build_to_complete(self, build_task_id, timeout=7200,
                                 poll_period=180):
    expired_time = 0
    while expired_time < timeout:
      if self.is_build_complete(build_task_id):
        break
      time.sleep(poll_period)
      expired_time += poll_period

    jita=JitaRest()
    status = jita.get_build_task(build_task_id).get_status()
    if status != "passed":
      ERROR("Timed out waiting for build to complete or build failed. Status:"
            " %s" % status)
      return False
    return True
def run_test_on_nucloud(test=None,
                        username=None,
                        node_pool=None,
                        branch=None,
                        build_url=None,
                        build_type="opt",
                        preferred_hypervisor=None,
                        commit_id=None):
    """
  Run the given test on nucloud and return the job id if submit succeeds.
  """
    if not test:
        test = FLAGS.test_name
    if not username:
        username = USERNAME
    if not node_pool:
        node_pool = NODE_POOL
    if not branch:
        branch = FLAGS.branch
    if not preferred_hypervisor:
        preferred_hypervisor = FLAGS.hypervisor

    nucloud = NuCloudREST()
    INFO("Submitting job to Nucloud for commit id %s" % commit_id)
    response_obj = nucloud.submit_job(
        [test],
        username,
        node_pool,
        branch=branch,
        build_url=build_url,
        build_type=build_type,
        preferred_hypervisor=preferred_hypervisor,
        commit_id=commit_id,
        skip_email_report=True)

    print response_obj.get_message()
    if response_obj.is_success():
        return response_obj.get_job_id()
    else:
        ERROR("Failed to trigger job in nucloud %s " %
              response_obj.get_message())
        return False
  def binary_search_commit(self, commit_search_list, input_type):
    """
    This is the main function that implements the binary search flow through the
    given commit_search_list.
  
    Params:
        commit_search_list: The list of gerrit change ids or commits to be
                            searched
        test: test set name
        node_pool: The node_pool to use to trigger the tests
        input_type: String to indicate type of input for the commits
        branch: The branch on which this commit appears
        hypervisor: The hypervisor that needs to be used  
    """
    INFO("Below are the list of commits being searched:\n%s" %
         pprint.pformat(commit_search_list))

    if len(commit_search_list) == 0:
      ERROR ("Length of commit_search_list is 0, this is probably a bug")
      return None

    elif len(commit_search_list) == 1:
      INFO("Returning %s " % commit_search_list[0])
      return commit_search_list[0]

    elif len(commit_search_list) == 2:
      if commit_search_list[0] in self.global_results_dict.keys():
        if self.global_results_dict[commit_search_list[0]]:
          return commit_search_list[1]
        else:
          return commit_search_list[0]
      if commit_search_list[1] in self.global_results_dict.keys():
        if self.global_results_dict[commit_search_list[1]]:
          return commit_search_list[0]

      # We reach here if we don't already have the test results for at least the
      # first commit
      response_map = {}
      response_map[commit_search_list[0]] = self.run_test_on_nucloud(
        build_url=self.commits_dict[commit_search_list[0]],
        commit_id=commit_search_list[0], input_type=input_type)
      self.wait_for_test_results(response_map)

      if self.global_results_dict[commit_search_list[0]]:
        return commit_search_list[1]
      else:
        return commit_search_list[0]

    # Get the number of free clusters from the pool.
    free_nodes = self.get_free_nodes_from_jarvis()
    num_free_clusters = len(free_nodes)/3
    INFO("free clusters in nucloud: %s " % num_free_clusters)
    search_list_len = len(commit_search_list)

    # If the number of free clusters is less than the number of commits,
    # let us do a binary search.
    if num_free_clusters < search_list_len:
      mid_commit_index = search_list_len / 2
      first_half_mid_commit_index = mid_commit_index / 2
      second_half_mid_commit_index = (
        mid_commit_index + 1 + search_list_len) / 2
      index_list = [mid_commit_index, first_half_mid_commit_index,
                    second_half_mid_commit_index]
      INFO("Commits selected for verification are: %s, %s and %s" % (
        commit_search_list[mid_commit_index], commit_search_list[
          first_half_mid_commit_index], commit_search_list[
          second_half_mid_commit_index]))

      response_map = {}
      for index in index_list:
        # If we already have the test result for this commit don't run the test
        # again.
        if commit_search_list[index] in self.global_results_dict.keys():
          continue

        response_map[commit_search_list[index]] = self.run_test_on_nucloud(
          build_url=self.commits_dict[commit_search_list[index]],
          commit_id=commit_search_list[index], input_type=input_type)

      self.wait_for_test_results(response_map)
      INFO("Results from the run are: %s" % self.global_results_dict)

      # Based on the test result, call the function again.
      if not self.global_results_dict[commit_search_list[
        first_half_mid_commit_index]]:
        INFO("Narrowing the search based on the results to commits between "
             "%s and %s" % (commit_search_list[0], commit_search_list[
              first_half_mid_commit_index]))
        return self.binary_search_commit(commit_search_list[
          0:(first_half_mid_commit_index+1)], input_type)
      elif not self.global_results_dict[commit_search_list[mid_commit_index]]:
        INFO("Narrowing the search based on the results to commits between "
             "%s and %s" % (commit_search_list[first_half_mid_commit_index],
                            commit_search_list[mid_commit_index]))
        return self.binary_search_commit(
          commit_search_list[first_half_mid_commit_index:(mid_commit_index+1)],
          input_type)
      elif not self.global_results_dict[commit_search_list[
        second_half_mid_commit_index]]:
        INFO("Narrowing the search based on the results to commits between "
             "%s and %s" % (commit_search_list[mid_commit_index],
                            commit_search_list[second_half_mid_commit_index]))
        return self.binary_search_commit(
          commit_search_list[mid_commit_index:(second_half_mid_commit_index+1)],
          input_type)
      else:
        INFO("Narrowing the search based on the results to commits between "
             "%s and %s" % (commit_search_list[second_half_mid_commit_index],
                            commit_search_list[-1]))
        return self.binary_search_commit(
          commit_search_list[second_half_mid_commit_index:], input_type)
    else:
      # We have enough clusters. Trigger all the runs in parallel.
      response_map = {}
      for commit in commit_search_list:
        if commit in self.global_results_dict.keys():
          continue
        response_map[commit] = self.run_test_on_nucloud(
          build_url=self.commits_dict[commit],
          commit_id=commit, input_type=input_type)

      self.wait_for_test_results(response_map)
      INFO("Results from the run are: %s" % self.global_results_dict)

      for commit in commit_search_list:
        if not self.global_results_dict[commit]:
          INFO("Returning the offending commit %s" % commit)
          return commit
  def transfer_powershell_module(uvm, out_dir, port,
                                 username="******",
                                 password="******"):
    """
    Transfer Powershell modules to the VM at
    ${Env:ProgramFiles}\WindowsPowershell\Modules.
    uvm: Windows VM for which the Powershell module needs to be transferred.
    out_dir: Test runner output directory from where the files should be
             copied.
    port: Http server port from which the Windows VM will be able to pull the
          modules.
    username: Username of the account to access the Windows VM
    password: Password for the above account.
    Returns True on success, False on failure.
    """
    hyperv_ps_modules_dir = (
        "%s/%s" % (top_dir(), WindowsVMCommandUtil.WINDOWS_VM_MODULE_PATH))
    agave_posh_modules = []
    for (root, _, filenames) in os.walk(hyperv_ps_modules_dir):
      for filename in filenames:
        if filename.endswith(".psm1"):
          module_path = os.path.join(root, filename)
          agave_posh_modules.append(module_path)
    for agave_posh_module in agave_posh_modules:
      try:
        module_basename = os.path.basename(agave_posh_module)
        os.symlink(agave_posh_module, "%s/%s" % (out_dir, module_basename))
      except OSError as ose:
        if ose.errno != errno.EEXIST:
          ERROR("Failed to create a symlink to the Hyper-V Agave PS module "
                "in %s: %s" % (out_dir, str(ose)))

    succeeded = True
    for agave_posh_module in agave_posh_modules:
      module_basename = os.path.basename(agave_posh_module)
      module_name_no_extension = module_basename.rsplit(".psm1")[0]
      remote_path = ("${Env:ProgramFiles}\WindowsPowershell\Modules\%s" %
                     module_name_no_extension)
      INFO("Transferring the NutanixWindows Powershell modules to %s"
           % uvm.ip())

      # Determine the local IP that has reachability to this host.
      sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
      sock.connect((uvm.ip(), 80)) # Port number doesn't matter.
      local_ip = sock.getsockname()[0]
      sock.close()
      install_posh_module_cmd = """
        $ErrorActionPreference = "Stop"
        $dest = New-Item -ItemType Directory -Path {remote_path} -Force
        Invoke-WebRequest http://{ip}:{port}/output/{module_name} `
          -OutFile $dest\\{module_name}""".format(remote_path=remote_path,
                                                  ip=local_ip, port=port,
                                                  module_name=module_basename)
      if FLAGS.agave_verbose:
        INFO("Transferring the %s Powershell module to %s using command: %s" %
             (module_name_no_extension, uvm.ip(), install_posh_module_cmd))
      ret, _, stderr = WindowsVMCommandUtil.execute_command(
          uvm, install_posh_module_cmd, username=username, password=password)
      if ret or stderr.strip():
        ERROR("Failed transferring %s Powershell module to %s: %s" %
              (module_name_no_extension, uvm.ip(), stderr))
        succeeded = succeeded and False
    return succeeded
        print "%s\nUsage: %s ARGS\n%s" % (err, sys.argv[0], FLAGS)
        sys.exit(1)

    file_template = "run_test_log_%d" % (int(time.time()))
    setup_logging(file_template)

    while True:
        top_dir = os.environ['TOP']
        filename = top_dir + "/" + FLAGS.last_good_commit_file
        f = open(filename)
        last_good_commit = f.read()
        f.close()
        latest_commit = get_latest_commit()
        job_id = run_test_on_nucloud(commit_id=latest_commit)
        if not job_id:
            ERROR("Trigerring test on Nucloud failed")
        if not wait_for_test_result(job_id):
            # Trigger auto bisect
            auto_bisect = Auto_Bisect(last_good_commit, latest_commit)
            offending_commit = auto_bisect.find_offending_commit()
            FATAL("Commit %s has broken the test" % offending_commit)
        else:
            f = open(filename, "w")
            f.write(latest_commit)
            f.close()
            last_good_commit = latest_commit
            latest_commit = get_latest_commit()
            commits = get_commits_in_range(last_good_commit, latest_commit)
            while len(commits) < 10:
                # Sleep for 10 mins
                time.sleep(600)
 def log_error(self, msg):
   """
   See superclass for documentation.
   """
   ERROR(msg)