private void provisionWithWait(DockerComputerSingle computer, TaskListener listener)
            throws Exception {
        final PrintStream logger = listener.getLogger();

        final Run run = computer.getRun();
        final DockerSlaveSingle slave = computer.getNode();
        if (isNull(slave)) {
            throw new IllegalStateException("Can't get slave for " + computer.getNode());
        }
        final DockerClient client = slave.getConnector().getClient();
        final DockerContainerLifecycle containerLifecycle = slave.getConfig().getDockerContainerLifecycle();

        final String imageId = containerLifecycle.getImage();

        //pull image
        logger.println("Pulling image " + imageId + "...");
        containerLifecycle.getPullImage().exec(client, imageId, listener);

        logger.println("Trying to create container for " + imageId);
        LOG.info("Trying to create container for {}", imageId);
        final DockerCreateContainer createContainer = containerLifecycle.getCreateContainer();
        CreateContainerCmd containerConfig = client.createContainerCmd(imageId);
        // template specific options
        createContainer.fillContainerConfig(containerConfig, null);

        // cloud specific options
        appendContainerConfig(containerConfig);

        // create
        CreateContainerResponse createResp = containerConfig.exec();
        String cId = createResp.getId();
        setContainerId(cId);
        logger.println("Created container " + cId + ", for " + run.getDisplayName());
        LOG.debug("Created container {}, for {}", cId, run.getDisplayName());
        // start
        StartContainerCmd startCommand = client.startContainerCmd(cId);
        startCommand.exec();
        logger.println("Started container " + cId);
        LOG.debug("Started container '{}', for '{}'.", cId, run.getDisplayName());

        boolean running = false;
        long launchTime = System.currentTimeMillis();
        while (!running &&
                TimeUnit2.SECONDS.toMillis(launchTimeout) > System.currentTimeMillis() - launchTime) {
            try {
                InspectContainerResponse inspectResp = client.inspectContainerCmd(cId).exec();
                if (isTrue(inspectResp.getState().getRunning())) {
                    logger.println("Container is running.");
                    LOG.debug("Container '{}' is running.", cId);
                    running = true;
                } else {
                    logger.println("Container is not running...");
                }
            } catch (ProcessingException ignore) {
            }
            Thread.sleep(1000);
        }

        if (!running) {
            listener.error("Failed to run container for %s, clean-up container", imageId);
            LOG.error("Failed to run container for {}, clean-up container", imageId);
            printLog(client, listener, cId);
            throw new IllegalStateException("Container is not running!");
        }

        // now real launch
        final String rootUrl = getJenkinsUrl(Jenkins.getInstance().getRootUrl());
//        Objects.requireNonNull(rootUrl, "Jenkins root url is not specified!");
        if (isNull(rootUrl)) {
            listener.fatalError("Jenkins root url is not specified!");
            containerLifecycle.getRemoveContainer().exec(client, cId);
            throw new IllegalStateException("Jenkins root url is not specified!");
        }

        final DockerSlaveSingle node = computer.getNode();
        if (isNull(node)) {
            listener.error("Failed to run container for %s", imageId);
            printLog(client, listener, containerId);
            throw new IllegalStateException("Node for computer: '" + computer.getName() +
                    "' can't be null, probably remote node disappeared.");
        }

        // exec jnlp connection in running container
        // TODO implement PID 1 replacement
        String startCmd =
                "cat << EOF > /tmp/config.sh.tmp && cd /tmp && mv config.sh.tmp config.sh\n" +
                        "JENKINS_URL=\"" + rootUrl + NL +
                        "JENKINS_USER=\"" + getUser() + NL +
                        "JENKINS_HOME=\"" + node.getRemoteFS() + NL +
                        "COMPUTER_URL=\"" + computer.getUrl() + NL +
                        "COMPUTER_SECRET=\"" + computer.getJnlpMac() + NL +
                        "JAVA_OPTS=\"" + getJvmOpts() + NL +
                        "SLAVE_OPTS=\"" + getSlaveOpts() + NL +
                        "NO_CERTIFICATE_CHECK=\"" + isNoCertificateCheck() + NL +
                        "NO_RECONNECT_SLAVE=\"" + isNoReconnect() + NL +
                        "EOF" + "\n";

        try {
            final ExecCreateCmdResponse createCmdResponse = client.execCreateCmd(cId)
                    .withTty(true)
                    .withAttachStdin(false)
                    .withAttachStderr(true)
                    .withAttachStdout(true)
                    .withCmd("/bin/sh", "-cxe", startCmd.replace("$", "\\$"))
                    .exec();

            logger.println("Starting connection command for " + cId);
            LOG.info("Starting connection command for {}", cId);

            try (ExecStartResultCallback exec = client.execStartCmd(createCmdResponse.getId())
                    .withDetach(true)
                    .withTty(true)
                    .exec(new ExecStartResultCallback())
            ) {
                exec.awaitCompletion(10, SECONDS);
            } catch (NotFoundException ex) {
                listener.error("Can't execute command: " + ex.getMessage().trim());
                LOG.error("Can't execute jnlp connection command: '{}'", ex.getMessage().trim());
                throw ex;
            }
        } catch (Throwable ex) {
            listener.error("Can't execute command: " + ex.getMessage().trim());
            LOG.error("Can't execute jnlp connection command: '{}'", ex.getMessage().trim());
            throw ex;
        }

        LOG.info("Successfully executed jnlp connection for '{}'", cId);
        logger.println("Successfully executed jnlp connection for " + cId);

        // TODO better strategy
        launchTime = System.currentTimeMillis();
        while (computer.isReallyOffline() &&
                TimeUnit2.SECONDS.toMillis(launchTimeout) > System.currentTimeMillis() - launchTime) {
            logger.println("Waiting slave connection...");
            Thread.sleep(1000);
        }

        if (computer.isReallyOffline()) {
            LOG.info("Launch timeout, terminating slave based on '{}'", cId);
            logger.println("Launch timeout, terminating slave.");
            printLog(client, listener, cId);
            throw new IllegalStateException("Agent didn't connect after timeout.");
        }

        LOG.info("Launched slave '{}' '{}' based on '{}'",
                computer.getSlaveVersion(), computer.getName(), cId);
        logger.println("Launched slave for " + cId);
    }
private void provisionWithWait ( DockerComputerSingle computer , TaskListener listener ) throws Exception { final PrintStream logger = listener . getLogger ( ) ; final Run run = computer . getRun ( ) ; final DockerSlaveSingle slave = computer . getNode ( ) ; if ( isNull ( slave ) ) { throw new IllegalStateException ( "Can't get slave for " + computer . getNode ( ) ) ; } final DockerClient client = slave . getConnector ( ) . getClient ( ) ; final DockerContainerLifecycle containerLifecycle = slave . getConfig ( ) . getDockerContainerLifecycle ( ) ; final String imageId = containerLifecycle . getImage ( ) ; logger . println ( "Pulling image " + imageId + "..." ) ; containerLifecycle . getPullImage ( ) . exec ( client , imageId , listener ) ; logger . println ( "Trying to create container for " + imageId ) ; LOG . info ( "Trying to create container for {}" , imageId ) ; final DockerCreateContainer createContainer = containerLifecycle . getCreateContainer ( ) ; CreateContainerCmd containerConfig = client . createContainerCmd ( imageId ) ; createContainer . fillContainerConfig ( containerConfig , null ) ; appendContainerConfig ( containerConfig ) ; CreateContainerResponse createResp = containerConfig . exec ( ) ; String cId = createResp . getId ( ) ; setContainerId ( cId ) ; logger . println ( "Created container " + cId + ", for " + run . getDisplayName ( ) ) ; LOG . debug ( "Created container {}, for {}" , cId , run . getDisplayName ( ) ) ; StartContainerCmd startCommand = client . startContainerCmd ( cId ) ; startCommand . exec ( ) ; logger . println ( "Started container " + cId ) ; LOG . debug ( "Started container '{}', for '{}'." , cId , run . getDisplayName ( ) ) ; boolean running = false ; long launchTime = System . currentTimeMillis ( ) ; while ( ! running && TimeUnit2 . SECONDS . toMillis ( launchTimeout ) > System . currentTimeMillis ( ) - launchTime ) { try { InspectContainerResponse inspectResp = client . inspectContainerCmd ( cId ) . exec ( ) ; if ( isTrue ( inspectResp . getState ( ) . getRunning ( ) ) ) { logger . println ( "Container is running." ) ; LOG . debug ( "Container '{}' is running." , cId ) ; running = true ; } else { logger . println ( "Container is not running..." ) ; } } catch ( ProcessingException ignore ) { } Thread . sleep ( 1000 ) ; } if ( ! running ) { listener . error ( "Failed to run container for %s, clean-up container" , imageId ) ; LOG . error ( "Failed to run container for {}, clean-up container" , imageId ) ; printLog ( client , listener , cId ) ; throw new IllegalStateException ( "Container is not running!" ) ; } final String rootUrl = getJenkinsUrl ( Jenkins . getInstance ( ) . getRootUrl ( ) ) ; if ( isNull ( rootUrl ) ) { listener . fatalError ( "Jenkins root url is not specified!" ) ; containerLifecycle . getRemoveContainer ( ) . exec ( client , cId ) ; throw new IllegalStateException ( "Jenkins root url is not specified!" ) ; } final DockerSlaveSingle node = computer . getNode ( ) ; if ( isNull ( node ) ) { listener . error ( "Failed to run container for %s" , imageId ) ; printLog ( client , listener , containerId ) ; throw new IllegalStateException ( "Node for computer: '" + computer . getName ( ) + "' can't be null, probably remote node disappeared." ) ; } String startCmd = "cat << EOF > /tmp/config.sh.tmp && cd /tmp && mv config.sh.tmp config.sh\n" + "JENKINS_URL=\"" + rootUrl + NL + "JENKINS_USER=\"" + getUser ( ) + NL + "JENKINS_HOME=\"" + node . getRemoteFS ( ) + NL + "COMPUTER_URL=\"" + computer . getUrl ( ) + NL + "COMPUTER_SECRET=\"" + computer . getJnlpMac ( ) + NL + "JAVA_OPTS=\"" + getJvmOpts ( ) + NL + "SLAVE_OPTS=\"" + getSlaveOpts ( ) + NL + "NO_CERTIFICATE_CHECK=\"" + isNoCertificateCheck ( ) + NL + "NO_RECONNECT_SLAVE=\"" + isNoReconnect ( ) + NL + "EOF" + "\n" ; try { final ExecCreateCmdResponse createCmdResponse = client . execCreateCmd ( cId ) . withTty ( true ) . withAttachStdin ( false ) . withAttachStderr ( true ) . withAttachStdout ( true ) . withCmd ( "/bin/sh" , "-cxe" , startCmd . replace ( "$" , "\\$" ) ) . exec ( ) ; logger . println ( "Starting connection command for " + cId ) ; LOG . info ( "Starting connection command for {}" , cId ) ; try ( ExecStartResultCallback exec = client . execStartCmd ( createCmdResponse . getId ( ) ) . withDetach ( true ) . withTty ( true ) . exec ( new ExecStartResultCallback ( ) ) ) { exec . awaitCompletion ( 10 , SECONDS ) ; } catch ( NotFoundException ex ) { listener . error ( "Can't execute command: " + ex . getMessage ( ) . trim ( ) ) ; LOG . error ( "Can't execute jnlp connection command: '{}'" , ex . getMessage ( ) . trim ( ) ) ; throw ex ; } } catch ( Throwable ex ) { listener . error ( "Can't execute command: " + ex . getMessage ( ) . trim ( ) ) ; LOG . error ( "Can't execute jnlp connection command: '{}'" , ex . getMessage ( ) . trim ( ) ) ; throw ex ; } LOG . info ( "Successfully executed jnlp connection for '{}'" , cId ) ; logger . println ( "Successfully executed jnlp connection for " + cId ) ; launchTime = System . currentTimeMillis ( ) ; while ( computer . isReallyOffline ( ) && TimeUnit2 . SECONDS . toMillis ( launchTimeout ) > System . currentTimeMillis ( ) - launchTime ) { logger . println ( "Waiting slave connection..." ) ; Thread . sleep ( 1000 ) ; } if ( computer . isReallyOffline ( ) ) { LOG . info ( "Launch timeout, terminating slave based on '{}'" , cId ) ; logger . println ( "Launch timeout, terminating slave." ) ; printLog ( client , listener , cId ) ; throw new IllegalStateException ( "Agent didn't connect after timeout." ) ; } LOG . info ( "Launched slave '{}' '{}' based on '{}'" , computer . getSlaveVersion ( ) , computer . getName ( ) , cId ) ; logger . println ( "Launched slave for " + cId ) ; }
Provision slave container and wait for it's availability.