@Override
  public Future<Slave> install(Jenkins j) {
    ManagedCredentials credential = new ManagedCredentials(j);

    try {
      credential.open();
      if (credential.getElement(
              By.xpath(
                  String.format(
                      "//input[@name='_.username'][@value='%s']"
                          + "/../../..//input[@name='_.description'][@value='%s']",
                      machine.getUser(), fingerprint)))
          == null) {
        SshPrivateKeyCredential sc = credential.add(SshPrivateKeyCredential.class);
        sc.username.set(machine.getUser());
        sc.description.set(fingerprint);
        sc.selectEnterDirectly().privateKey.set(keyPair.readPrivateKey());
        credential.save();
      }
    } catch (IOException e) {
      throw new AssertionError(e);
    }

    final Slave s = create(machine.getPublicIpAddress(), j);

    // Slave is configured, now wait till its online
    return new Future<Slave>() {

      @Override
      public boolean cancel(boolean mayInterruptIfRunning) {
        return false;
      }

      @Override
      public boolean isCancelled() {
        return slaveWaitComplete.get();
      }

      @Override
      public boolean isDone() {
        return slaveWaitComplete.get() || s.isOnline();
      }

      @Override
      public Slave get() throws InterruptedException, ExecutionException {
        waitForOnLineSlave(s, slaveReadyTimeOutInSec);
        return s;
      }

      @Override
      public Slave get(long timeout, TimeUnit unit)
          throws InterruptedException, ExecutionException, TimeoutException {
        if (unit != TimeUnit.SECONDS) {
          timeout = unit.toSeconds(timeout);
        }
        waitForOnLineSlave(s, (int) timeout);
        return s;
      }
    };
  }
  private Slave create(String host, Jenkins j) {
    // Just to make sure the dumb slave is set up properly, we should seed it
    // with a FS root and executors
    final DumbSlave s = j.slaves.create(DumbSlave.class);

    s.find(by.input("_.host")).sendKeys(host);

    sleep(25);

    final Select cId = new Select(s.find(by.input("_.credentialsId")));
    final String credentialName = String.format("%s (%s)", machine.getUser(), fingerprint);
    s.waitForCond(
        new Callable<Object>() {
          @Override
          public Object call() throws Exception {
            List<WebElement> options = cId.getOptions();
            for (WebElement e : options) {
              if (credentialName.equals(e.getText())) return true;
            }
            return false;
          }
        });
    cId.selectByVisibleText(credentialName);
    s.setExecutors(1);

    s.save();
    return s;
  }